Definition of design pattern
Software Design pattern, also known as Design pattern, is a set of code design experience that is repeatedly used, known by most people, classified and catalogued. The purpose of using Design pattern is to reuse code, make code easier to be understood by others, ensure code reliability and program reusability.
Opening and closing principle: expansion is encouraged, but modification is rejected (or not recommended). For example, functions V2 and V3 often appear in BFF.
Classification of design patterns
Generally speaking, design patterns are divided into three categories:
There are five kinds of creation patterns: factory method pattern, abstract factory pattern, singleton pattern, builder pattern and prototype pattern.
There are seven structural modes: adapter mode, decorator mode, agent mode, appearance mode, bridge mode, combination mode and sharing mode.
There are eleven behavioral modes: strategy mode, template method mode, observer mode, iteration sub mode, responsibility chain mode, command mode, memo mode, status mode, visitor mode, mediator mode and interpreter mode.
1, Singleton mode
Concept:
- A singleton class can only have one instance.
- A singleton class must create its own unique instance.
- A singleton class must provide this instance to all other objects.
As node JS code as an example:
//Class definition class HttpManager { constructor() { } } exports.http = new HttpManager(); //main.js const HttpManager = require('./HttpManager.js'); async function main() { let http = new HttpManager(); global.http = http; //I think it is the key code } main();
advantage:
- There is only one instance in memory to reduce memory overhead without considering multiple occupation of resources.
- In Nodejs, you can call the methods of these classes globally without importing modules.
Disadvantages:
- In vscade, the implementation of singleton class in this way can not jump the code, which greatly tests the ability to understand the system.
- There is no interface and cannot inherit (private). It conflicts with the principle of single responsibility. A class should only care about the internal logic and not how to instantiate it outside.
If the singleton class is designed, there may be no logic to add and unlock resources inside? So don't let others inherit?
2, Factory mode
The simple factory pattern belongs to the class creation pattern, also known as the static factory method pattern. By specifically defining a class to be responsible for creating instances of other classes, the created instances usually have a common parent class.
Actual scenario:
-
In the graphical library, single line and multi line edit columns inherit the editing function of the base class, but they are expanded respectively. (is it factory mode?)
-
Designing a framework for connecting to a server requires three protocols, "POP3", "IMAP" and "HTTP", which can be used as product classes to jointly implement an interface.
-
odbc, golang and Java of the database provide packages to connect to the database.
effect:
-
The factory pattern is to decouple: separate the process of creating and using objects. If Class A wants to call Class B, then A just calls the method of B, and the instantiation of B is handed over to the factory class.
-
Factory mode can reduce code duplication. If the process of creating object B is very complex, requires a certain amount of code, and needs to be used in many places, there will be a lot of duplicate code. We can put the code for creating object B into the factory for unified management. It not only reduces repeated code, but also facilitates the modification and maintenance of the creation process of B in the future.
-
Because the factory manages the object creation logic, users do not need to know the specific creation process, just use it, which reduces the errors caused by the user's creation logic. (such as database operation, mysql, oracle, etc.)
3, Abstract factory pattern
Abstract Factory Pattern is to create other factories around a super factory. This super factory is also called the factory of other factories. This type of design pattern belongs to creation mode, which provides the best way to create objects.
In the abstract factory pattern, an interface is a factory responsible for creating a related object, and there is no need to explicitly specify their classes. Each generated factory can provide objects according to the factory pattern.
4, Builder mode
Builder Pattern uses multiple simple objects to build a complex object step by step. This type of design pattern belongs to creation mode, which provides the best way to create objects.
A Builder class will construct the final object step by step. The Builder class is independent of other objects.
In short, it is the process of continuously expanding classes:
- Create a static internal class Builder in Computer, and then copy all the parameters in Computer into the Builder class.
- Create a private constructor in Computer with the parameter of Builder type
- Create a public constructor in Builder. The parameters are those required in Computer, cpu and ram.
- Create a setting function in Builder, assign values to those optional parameters in Computer, and the return value is an instance of Builder type
- Create a build() method in Builder, build an instance of Computer and return
public class Computer { private final String cpu;//must private final String ram;//must private final int usbCount;//Optional private final String keyboard;//Optional private final String display;//Optional private Computer(Builder builder){ this.cpu=builder.cpu; this.ram=builder.ram; this.usbCount=builder.usbCount; this.keyboard=builder.keyboard; this.display=builder.display; } public static class Builder{ private String cpu;//must private String ram;//must private int usbCount;//Optional private String keyboard;//Optional private String display;//Optional public Builder(String cup,String ram){ this.cpu=cup; this.ram=ram; } public Builder setUsbCount(int usbCount) { this.usbCount = usbCount; return this; } public Builder setKeyboard(String keyboard) { this.keyboard = keyboard; return this; } public Builder setDisplay(String display) { this.display = display; return this; } public Computer build(){ return new Computer(this); } } //Omit getter method } Computer computer=new Computer.Builder("intel ","Samsung") .setDisplay("Samsung 24 inch") .setKeyboard("Logitech") .setUsbCount(2) .build();
5, Prototype mode
Using an instance that has been created as a prototype, create a new object that is the same or similar to the prototype by copying the prototype object. Here, the prototype instance specifies the kind of object to create. Creating objects in this way is very efficient, and you don't need to know the details of object creation at all. For example, the installation of Windows operating system is usually time-consuming, and replication is much faster.
Advantages of prototype mode:
- Java's built-in prototype pattern is based on the replication of memory binary stream, and its performance is better than that of directly new an object.
- You can use deep cloning to save the state of an object, and use prototype mode to copy an object and save its state, which simplifies the process of creating an object for use when needed (for example, restoring to a certain state in History), and can assist in the implementation of undo.
Disadvantages of prototype mode:
- You need to configure a clone method for each class.
- The clone method is located inside the class. When modifying an existing class, you need to modify the code, which violates the opening and closing principle.
- When implementing deep cloning, you need to write more complex code, and when there are multiple nested references between objects, in order to implement deep cloning, the classes corresponding to each layer of objects must support deep cloning, which will be troublesome to implement. Therefore, deep cloning and shallow cloning need to be used properly.
The cloning of prototype pattern can be divided into shallow cloning and deep cloning.
-
Shallow cloning: create a new object. The properties of the new object are exactly the same as the original object. For non basic type properties, it still points to the memory address of the object pointed to by the original property.
-
Deep clone: when a new object is created, other objects referenced in the attribute will also be cloned and no longer point to the original object address.
import java.util.*; interface Shape extends Cloneable { public Object clone(); //Copy public void countArea(); //Calculated area } class Circle implements Shape { public Object clone() { Circle w = null; try { w = (Circle) super.clone(); } catch (CloneNotSupportedException e) { System.out.println("Copy circle failed!"); } return w; } public void countArea() { int r = 0; System.out.print("This is a circle. Please enter the radius of the circle:"); Scanner input = new Scanner(System.in); r = input.nextInt(); System.out.println("Area of the circle=" + 3.1415 * r * r + "\n"); } } class Square implements Shape { public Object clone() { Square b = null; try { b = (Square) super.clone(); } catch (CloneNotSupportedException e) { System.out.println("Copy square failed!"); } return b; } public void countArea() { int a = 0; System.out.print("This is a square. Please enter its side length:"); Scanner input = new Scanner(System.in); a = input.nextInt(); System.out.println("The area of the square=" + a * a + "\n"); } } class ProtoTypeManager { private HashMap<String, Shape> ht = new HashMap<String, Shape>(); public ProtoTypeManager() { ht.put("Circle", new Circle()); ht.put("Square", new Square()); } public void addshape(String key, Shape obj) { ht.put(key, obj); } public Shape getShape(String key) { Shape temp = ht.get(key); return (Shape) temp.clone(); } } public class ProtoTypeShape { public static void main(String[] args) { ProtoTypeManager pm = new ProtoTypeManager(); Shape obj1 = (Circle) pm.getShape("Circle"); obj1.countArea(); Shape obj2 = (Shape) pm.getShape("Square"); obj2.countArea(); } }
6, Adapter mode
Convert the interface of a class into another interface that the customer wants. The adapter pattern allows classes that cannot work together because of interface incompatibility to work together.
purpose
It mainly solves that in the software system, some "existing objects" are often put into the new environment, and the interface required by the new environment can not be met by the existing objects.
public class AC110 implements AC { public final int output = 110; @Override public int outputAC() { return output; } } public class AC220 implements AC { public final int output = 220; @Override public int outputAC() { return output; } }
advantage:
- You can let any two classes that are not associated run together.
- Class reuse is improved.
- Increased class transparency.
- Good flexibility.
Disadvantages:
Excessive use of adapters will make the system very messy and difficult to grasp as A whole. For example, it is obvious that the A interface is called, but in fact, it is internally adapted to the implementation of B interface. If this happens too often in A system, it is tantamount to A disaster. Therefore, if it is not necessary, you can refactor the system directly instead of using adapters.
7, Bridging mode
Bridge is used to decouple abstraction and realization, so that they can change independently. This type of design pattern belongs to structural pattern, which realizes the decoupling of abstraction and realization by providing a bridge structure between abstraction and realization.
This pattern involves an interface as a bridge, so that the function of the entity class is independent of the interface implementation class. These two types of classes can be structurally changed without affecting each other.
It's no use.
8, Filter mode
The filter mode belongs to the structural mode. It achieves a unified filter standard by combining multiple different filter standards, so that the specific filter is isolated from the upper layer.
It's no use.
9, Combination mode
Composite Pattern, also known as partial overall pattern, is used to treat a group of similar objects as a single object. Composite Pattern combines objects according to tree structure to represent part and overall hierarchy. This type of design pattern belongs to structural pattern, which creates the tree structure of object group.
This pattern creates a class that contains its own group of objects. This class provides a way to modify the same object group.
It's no use.
10, Decorator mode
Decorator Pattern allows adding new functions to an existing object without changing its structure. This type of design pattern belongs to structural pattern, which is used as a wrapper for existing classes.
This pattern creates a decoration class to wrap the original class, and provides additional functions on the premise of maintaining the integrity of class method signature.
It's no use.
11, Observer mode
When there is a one to many relationship between objects, the Observer Pattern is used. For example, when an object is modified, it will automatically notify the objects that depend on it. The Observer Pattern is a behavioral pattern.
Classic event driven.
The two-way binding of Qt signal slot and Vue is realized by using observer mode.
12, MVC mode
The MVC pattern represents the model view controller pattern, which is used for hierarchical development of applications.
-
Model - a model represents an object or JAVA POJO that accesses data. It can also have logic to update the controller when data changes.
-
View - a view represents a visualization of the data contained in the model.
-
Controller - the controller acts on models and views. It controls the flow of data to model objects and updates the view as the data changes. It separates the view from the model.
MVC mode can only be used by web back-end development?
summary
Since the remaining design patterns are almost unavailable, I will summarize the design patterns used by the current applet BFF according to my personal understanding.
- Singleton class
BFF uses singleton classes and is "full of Chinese", because each class in our code will be instantiated almost once in the process, and the relevant classes will be instantiated only after the program runs to a module (because of the characteristics of JS).
If you instantiate all required classes immediately after the program starts, it is "hungry man style", which will be relatively easy for data management.
- Adapter mode
The work of BFF itself should be to adapt multiple systems and provide unified external interfaces. Personally, I think many of the filter methods actually do the work of adapters.
- Iterator mode
Bid farewell to the for loop through lodash and foreach.
anything else?