23 design patterns to help you write beautiful code gracefully

The principle or source code of each technology stack we usually use is more or less related to the concept of design patterns. It can also be said that only by better mastering design patterns, our code can be more standardized, concise and more efficient.

Secondly, most of the design patterns are repeatedly summarized through the experience of our predecessors. Standing on the shoulders of giants and absorbing their experience and lessons, our coding road will last longer.

At the same time, it is also an option to add points during our interview. If you can tell the design pattern to the interviewer, the interviewer will certainly look at you with new eyes. In the work, having a good design pattern idea will also be of great help to the development of the project.

Next, follow Xiaoyu to see what design patterns we need to know ~

preface

Generally speaking, design patterns are divided into three categories:

_ Create mode:_ Factory method pattern, abstract factory pattern, singleton pattern, builder pattern, prototype pattern.

_ Structural mode:_ Adapter mode, decorator mode, agent mode, appearance mode, bridge mode, combination mode and sharing mode.

_ Behavioral mode:_ Policy 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.

Singleton mode

concept

Ensure that a class has only one instance, instantiates itself and provides this instance to the whole system.

Usage scenario

  • Environment requiring generation of unique serial number;
  • A shared access point or shared data is required in the whole project, such as a counter on a Web page. You can use the singleton mode to maintain the counter value and ensure thread safety without recording each refresh in the database;
  • Creating an object consumes too many resources, such as accessing IO, database and other resources;
  • The environment that needs to define a large number of static constants and static methods (such as tool classes) can adopt the singleton mode (of course, it can also be declared as static directly).

Code example

Thread safe:

`public class Singleton {`
 `private static final Singleton singleton = new Singleton();`
 `//Limit the generation of multiple objects`
 `private Singleton(){`
 `}`
 `//The instance object is obtained by this method`
 `public static Singleton getSingleton(){`
 `return singleton;`
 `}`
 `//Other methods in the class should be static as far as possible`
 `public static void doSomething(){`
 `}`
`}`

Thread unsafe:

`public class Singleton {`
 `private static Singleton singleton = null;`
 `//Limit the generation of multiple objects`
 `private Singleton(){`
 `}`
 `//The instance object is obtained by this method`
 `public static Singleton getSingleton(){`
 `if(singleton == null){`
 `singleton = new Singleton();`
 `}`
 `return singleton;`
 `}`
`}`

Unsafe for threads:

Add the synchronized keyword before the getSingleton method, or add synchronized in the getSingleton method.

Factory mode

concept

Define an interface for creating objects and let subclasses decide which class to instantiate. Factory methods delay instantiation of a class to its subclasses.

Usage scenario

jdbc connection database, hardware access, reduce the generation and destruction of objects

structure

_ Simple factory mode:_ A module only needs a factory class. There is no need to generate it and use static methods

_ Multiple factory classes:_ Each race (specific product category) corresponds to a creator. Each creator is independently responsible for creating the corresponding product object, which is very consistent with the principle of single responsibility

_ Instead of singleton mode:_ The core requirement of singleton mode is that there is only one object in memory, and only one object can be produced in memory through factory method mode

_ Delayed initialization:_ ProductFactory is responsible for the creation of product class objects, and generates a cache through the prMap variable to retain objects that need to be reused again

Code example

Product is an abstract product class, which is responsible for defining the commonness of products and realizing the most abstract definition of things;

Creator creates a class for abstraction, that is, an abstract factory. How to create a product class is completed by the concrete implementation factory ConcreteCreator.

`public class ConcreteCreator extends Creator {`
 `public <T extends Product> T createProduct(Class<T> c){`
 `Product product=null;`
 `try {`
 `product =`
 `(Product)Class.forName(c.getName()).newInstance();`
 `} catch (Exception e) {`
 `//Exception handling`
 `}`
 `return (T)product;`
 `}`
`}`

Abstract factory pattern

concept

Provides an interface for creating a set of related or interdependent objects without specifying their specific classes.

Usage scenario

An object family (or a group of objects that have no relationship) has the same constraints.

When different operating systems are involved, you can consider using the abstract factory pattern.

Code example

`public abstract class AbstractCreator {`
 `//Create A product family`
 `public abstract AbstractProductA createProductA();`
 `//Create B # product family`
 `public abstract AbstractProductB createProductB();`
`}`

Template method pattern

concept

Define the framework of an algorithm in operation, and delay some steps to subclasses. The subclass can redefine some specific steps of an algorithm without changing the structure of the algorithm.

Usage scenario

  • When multiple subclasses have public methods and the logic is basically the same.
  • For important and complex algorithms, the core algorithm can be designed as a template method, and the surrounding detailed functions are realized by each subclass.
  • During refactoring, the template method pattern is a frequently used pattern. Extract the same code into the parent class, and then restrict its behavior through hook functions (see "extension of template method pattern").

structure

Abstract template: AbstractClass is an abstract template. Its methods are divided into two categories:

1. Basic method: also called basic operation, it is a method implemented by subclasses and called in template methods.

2. Template method: there can be one or several, generally a specific method, that is, a framework to schedule the basic methods and complete the fixed logic.

Note: in order to prevent malicious operations, the keyword "final" is added to the general template method, and it is not allowed to be overwritten.

_ Specific template:_ Implement one or more abstract methods defined by the parent class, that is, the basic methods defined by the parent class can be implemented in the child class.

Code example

`package templateMethod;`
`public class TemplateMethodPattern`
`{`
 `public static void main(String[] args)`
 `{`
 `AbstractClass tm=new ConcreteClass();`
 `tm.TemplateMethod();`
 `}`
`}`
`//Abstract class`
`abstract class AbstractClass`
`{`
 `public void TemplateMethod() //Template method`
 `{`
 `SpecificMethod();`
 `abstractMethod1();`
 `abstractMethod2();`
 `}`
 `public void SpecificMethod() //Specific method`
 `{`
 `System.out.println("Concrete methods in abstract classes are called...");`
 `}`
 `public abstract void abstractMethod1(); //Abstract method 1`
 `public abstract void abstractMethod2(); //Abstract method 2`
`}`
`//Specific subclass`
`class ConcreteClass extends AbstractClass`
`{`
 `public void abstractMethod1()`
 `{`
 `System.out.println("The implementation of abstract method 1 is called...");`
 `}`
 `public void abstractMethod2()`
 `{`
 `System.out.println("The implementation of abstract method 2 is called...");`
 `}`
`}`

Builder pattern

concept

Separate the construction of a complex object from its representation, so that the same construction process can create different representations.

Usage scenario

  • When the same method, different execution sequences and different event results are generated, the builder mode can be adopted.
  • Multiple assemblies or parts can be assembled into one object, but the running results are different, you can use this mode.
  • The product class is very complex, or the calling order in the product class is different, resulting in different performance. At this time, it is very appropriate to use the builder mode.

structure

_ Product category:_ It usually implements the template method pattern, that is, there are template methods and basic methods.

_ Builder Abstract Builder:_ The establishment of standardized products is generally realized by subclasses.

_ ConcreteBuilder specific Builder:_ Implement all the methods defined by the abstract class and return a grouped object.

_ Director class:_ Be responsible for arranging the order of existing modules, and then tell Builder to start construction

Code example

`public class ConcreteProduct extends Builder {`
 `private Product product = new Product();`
 `//Set up product parts`
 `public void setPart(){`
 `/*`
 `* Logical processing within product class`
 `*/`
 `}` 
 `//Build a product`
 `public Product buildProduct() {`
 `return product;`
 `}`
`}`

proxy pattern

concept

Provide a proxy for other objects to control access to this object.

structure

_ Subject abstract theme role:_ The abstract topic class can be either an abstract class or an interface. It is the most common business type definition without special requirements.

_ RealSubject specific subject role:_ It is also called delegated role and delegated role. It is the head of injustice and the specific executor of business logic.

_ Proxy subject role:_ It is also called delegate class and agent class. It is responsible for the application of real roles, delegating the methods and restrictions defined by all abstract topic classes to the implementation of real topic roles, and doing pre-processing and post-processing before and after the processing of real topic roles.

classification

_ General agent:_ In this mode, the caller only knows the agent without knowing who the real role is, shielding the impact of the change of the real role on the high-level module. The real subject role can be modified as it wants, and has no impact on the high-level module. As long as you implement the method corresponding to the interface, this mode is very suitable for occasions with high scalability requirements.

_ Mandatory agent:_ The concept of mandatory proxy is to find the proxy role from the real role, and direct access to the real role is not allowed. As long as the high-level module calls getProxy, it can access all the methods of the real role. It does not need to generate a proxy at all. The management of the proxy has been completed by the real role itself.

  • Difference: a general agent is that we need to know the existence of an agent before we can access it; Forced proxy is that the caller directly calls the real role without caring about the existence of the proxy. The generation of the proxy is determined by the real role.

_ Dynamic proxy:_ Generate all methods according to the proxy interface, that is, given an interface, the dynamic proxy will declare that "I have implemented all methods under the interface". Two independent development lines. The dynamic agent realizes the responsibilities of the agent, and the business logic realizes the relevant logical functions. There is no inevitable coupling relationship between the two. The notification cuts in from another aspect, and finally couples in the high-level module to complete the logical encapsulation task.

  • Intent: cross-sectional programming to enhance or control the behavior of objects without changing our existing code structure.
  • First condition: the proxied class must implement an interface.

Code example

`public Object getProxy(@Nullable ClassLoader classLoader) {`
 `if (logger.isTraceEnabled()) {`
 `logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());`
 `}`
 `Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);`
 `findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);`
 `return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);`
`}`

Prototype mode

concept

Specify the type of objects to be created with prototype instances, and create new objects by copying these prototypes.

Usage scenario

_ Resource optimization scenario:_ Class initialization needs to digest a lot of resources, including data, hardware resources, etc.

_ Scenarios with performance and safety requirements:_ If generating an object through new requires very cumbersome data preparation or access rights, you can use the prototype pattern.

_ Scene of one object with multiple modifiers:_ When an object needs to be accessed by other objects, and each caller may need to modify its value, you can consider using the prototype pattern to copy multiple objects for the caller.

advantage

The prototype pattern actually implements the clonable interface and overrides the clone () method.

_ Excellent performance:_ The prototype pattern is a copy of the binary stream in memory, which is much better than directly new an object. Especially when a large number of objects are generated in a loop, the prototype pattern can better reflect its advantages.

_ Escape constructor constraints:_ This is both its advantage and disadvantage. If it is copied directly in memory, the constructor will not be executed.

Code example

`public class PrototypeClass implements Cloneable{`
 `//Overriding the {Object} method of the parent class`
 `@Override`
 `public PrototypeClass clone(){`
 `PrototypeClass prototypeClass = null;`
 `try {`
 `prototypeClass = (PrototypeClass)super.clone();`
 `} catch (CloneNotSupportedException e) {`
 `//Exception handling`
 `}`
 `return prototypeClass;`
 `}`
`}`

Intermediary model

concept

A mediation object is used to encapsulate a series of object interactions. The mediator makes the objects interact without display, so that their coupling is loose, and the interaction between them can be changed independently.

Usage scenario

The mediator pattern is applicable to the tight coupling between multiple objects. The standard of tight coupling is that there is a spider web structure in the class diagram, that is, each class is directly related to other classes.

structure

_ Mediator Abstract mediator role:_ The abstract mediator role defines a unified interface for communication between colleague roles.

_ Concrete Mediator role:_ The specific mediator role realizes the cooperative behavior by coordinating the roles of colleagues, so it must rely on the roles of colleagues.

_ Collague Colleague role:_ Every Colleague role knows the intermediary role, and when communicating with other Colleague roles, we must cooperate through the intermediary role. The behavior of each Colleague class is divided into two types: one is the behavior of the Colleague itself, such as changing the state of the object itself and dealing with his own behavior. This behavior is called self method, which has no dependence on other Colleague classes or intermediaries; the second is the behavior that can be completed only by relying on intermediaries, which is called dep method.

Sample code

`public abstract class Mediator {`
 `//Define colleague classes`
 `protected ConcreteColleague1 c1;`
 `protected ConcreteColleague2 c2;`
 `//Inject the colleague class through the {getter/setter} method`
 `public ConcreteColleague1 getC1() {`
 `return c1;`
 `}`
 `public void setC1(ConcreteColleague1 c1) {`
 `this.c1 = c1;`
 `}`
 `public ConcreteColleague2 getC2() {`
 `return c2;`
 `}`
 `public void setC2(ConcreteColleague2 c2) {`
 `this.c2 = c2;`
 `}`
 `//Business logic of mediator model`
 `public abstract void doSomething1();`
 `public abstract void doSomething2();`
`}`

Command mode

concept

Encapsulating a request into an object allows you to parameterize the client with different requests, queue requests or record request logs, which can provide command revocation and recovery functions.

Usage scenario

The command mode can be adopted where it is considered as a command. For example, in GUI development, the click of a button is a command, and the command mode can be adopted; When simulating DOS commands, of course, the command mode should also be adopted; Processing of trigger feedback mechanism, etc.

structure

_ Receive recipient role:_ This role is the working role. The command should be executed when it is passed here. Specifically, in our above example, there are three implementation classes of Group (requirement Group, art Group and code Group).

_ Command role:_ All commands that need to be executed are declared here.

_ Invoker caller role:_ The command is received and executed. In the example, I (Project Manager) is this role.

Code example

`public class Invoker {`
 `private Command command;`
 `//Set point injection`
 `public void setCommand(Command command) {`
 `this.command = command;`
 `}`
 `//Execute command`
 `public void action() {`
 `this.command.execute();`
 `}`
`}`

Responsibility chain model

concept

Multiple objects have the opportunity to process the request, thus avoiding the coupling relationship between the sender and receiver of the request. Connect these objects into a chain and pass the request along the chain until an object processes it.

duty

The abstract handler implements three responsibilities:

1. Define a request processing method handleMessage, which is the only method open to the public;

2. Define the arrangement method setNext of a chain and set the next handler;

3. It defines two methods that the specific requester must implement: define the level that he can handle, getHandlerLevel, and the specific processing task echo.

Code example

`public abstract class Handler {`
 `private Handler nextHandler;`
 `//Each handler must process the request`
 `public final Response handleMessage(Request request){`
 `Response response = null;`
 `//Determine whether it is your own processing level`
 `if(this.getHandlerLevel().equals(request.getRequestLevel())){`
 `response = this.echo(request);`
 `}else{ //Processing level that does not belong to itself`
 `//Determine whether there is a next processor`
 `if(this.nextHandler != null){`
 `response =`
 `this.nextHandler.handleMessage(request);`
 `}else{`
 `//If there is no proper handler, the business will be handled by itself`
 `} }`
 `return response;`
 `}`
 `//Set who is the next processor`
 `public void setNext(Handler _handler){`
 `this.nextHandler = _handler;`
 `}`
 `//Each processor has a processing level`
 `protected abstract Level getHandlerLevel();`
 `//Each processor must implement the processing task`
 `protected abstract Response echo(Request request);`
`}`

matters needing attention

The number of nodes in the chain needs to be controlled to avoid the occurrence of ultra long chain. The general practice is to set a maximum number of nodes in the Handler and judge whether it has exceeded its threshold in the setNext method. If it exceeds the threshold, the chain is not allowed to be established to avoid unintentional destruction of system performance.

Decoration mode

concept

Dynamically add some additional responsibilities to an object. In terms of adding functions, decoration pattern is more flexible than generating subclasses.

Usage scenario

  • You need to extend the function of a class or add additional functions to a class.
  • You need to dynamically add functions to an object, and these functions can be dynamically revoked.
  • It is necessary to modify or add functions for a batch of brother classes. Of course, it is the preferred decoration mode.

structure

_ Component abstract component:_ Component is an interface or abstract class, which defines our core object, that is, the most primitive object. In the decoration pattern, there must be a most basic, core and primitive interface or abstract class to act as a component abstract component.

_ ConcreteComponent specific components:_ ConcreteComponent is the implementation of the most core, primitive and basic interface or abstract class. What you want to decorate is it.

_ Decorator decorative role:_ It is generally an abstract class. What is it used for? To implement an interface or abstract method, there may not be an abstract method in it. In its properties, there must be a private variable pointing to the Component abstract Component.

_ Specific decorative roles:_ Two specific decoration categories, you should decorate your most core, primitive and basic things into other things.

Code example

`/**`
 `* Decorative role`
 `*/`
`@Data`
`@AllArgsConstructor`
`@NoArgsConstructor`
`@Log`
`class BufferedReader implements Reader{`
 `private  Reader reader;`
 `@Override`
 `public void read() {`
 `reader.read();`
 `}`
 `public void readLine(){`
 `read();`
 `log.info("And read only one line");`
 `}`
`}`

Strategy mode

concept

Define a set of algorithms, encapsulate each algorithm and make them interchangeable.

Usage scenario

  • Multiple classes have only slightly different scenarios in algorithm or behavior.
  • The algorithm needs to switch freely.
  • Scenarios that need to mask algorithm rules.
  • If the number of specific strategies exceeds 4, the mixed mode should be considered

structure

_ Context encapsulated role:_ It is also called context role, which serves as a connecting link between the preceding and the following, shields the direct access of high-level modules to policies and algorithms, and encapsulates possible changes.

_ Strategy Abstract policy role:_ The abstraction of a policy or algorithm family, usually an interface, defines the methods and attributes that each policy or algorithm must have.

_ ConcreteStrategy specific policy roles:_ Implement the operations in the abstract policy. This class contains specific algorithms.

Code example

`public enum Calculator {`
 `//Addition operation`
 `ADD("+"){`
 `public int exec(int a,int b){`
 `return a+b;`
 `}`
 `},`
 `//Subtraction operation`
 `SUB("-"){`
 `public int exec(int a,int b){`
 `return a - b;`
 `}`
 `};`
 `String value = "";`
 `//Define member value types`
 `private Calculator(String _value){`
 `this.value = _value;`
 `}`
 `//Gets the value of the enumeration member`
 `public String getValue(){`
 `return this.value;`
 `}`
 `//Declare an abstract function`
 `public abstract int exec(int a,int b);`
`}`

Adapter mode

concept

The interface of a class is transformed into another interface expected by the client, so that the two classes that cannot work together due to interface mismatch can work together.

Usage scenario

When you are motivated to modify an interface that is already in production, the adapter mode may be the best mode for you. For example, when the system is extended, you need to use an existing or newly established class, but this class does not conform to the system interface. What should I do? The adapter mode should not be considered in the detailed design stage. The main scenario is in the extended application.

Class Adapter

_ Target target role:_ This role defines what kind of interface to convert other classes, that is, our expected interface.

_ Adaptee source role:_ The "who" you want to convert into the target role is the source role. It is an existing and well running class or object. After being wrapped by the adapter role, it will become a new and beautiful role.

_ Adapter role:_ The core role of the adapter mode. The other two roles are existing roles, and the adapter role needs to be newly established. Its responsibility is very simple: how to convert the source role to the target role? By inheritance or class association.

object adapter

Instead of multiple inheritance or inheritance, use direct association, or delegate.

Differences between object adapter and class adapter:

Class adapter is the inheritance between classes, and object adapter is the composition relationship of objects, or the association relationship of classes, which is the fundamental difference between the two. In the actual project, there are relatively many scenes used by the object adapter.

Code example

`public class Adapter extends Target`
`{`
 `private Adaptee adaptee;`
 `public Adapter(Adaptee adaptee)`
 `{`
 `this.adaptee=adaptee;`
 `}`
 `public void request()`
 `{`
 `adaptee.specificRequest();`
 `}`
`}` 

Iterator mode

concept

It provides a way to access each element in a container object without exposing the internal details of the object.

structure

_ Iterator Abstract iterator:_ The abstract iterator is responsible for defining the interface for accessing and traversing elements, and basically has three fixed methods: first() obtains the first element, next() accesses the next element, and isDone() whether it has accessed the bottom (Java is called hasNext() method).

_ ConcreteIterator specific iterator:_ The specific iterator role should implement the iterator interface to complete the traversal of container elements.

_ Aggregate Abstract container:_ The container role is responsible for providing an interface to create a specific iterator role. It must provide a method like createIterator(), which is generally iterator() in Java.

_ Concrete Aggregate specific container:_ The concrete container implements the method defined by the container interface and creates the object containing the iterator.

Code example

`/**`
 `* Concrete iterator`
 `*/`
`public class ConcreteIterator<T> implements Iterator<T> {`
 `private List<T> list = new ArrayList<>();`
 `private int cursor = 0;`
 `public boolean hasNext() {`
 `return cursor != list.size();`
 `}`
 `public T next() {`
 `T obj = null;`
 `if (this.hasNext()) {`
 `obj = this.list.get(cursor++);`
 `}`
 `return obj;`
 `}`
`}`

Combination mode

concept

The objects are combined into a tree structure to represent the "part whole" hierarchy, so that users have consistency in the use of single objects and combined objects.

Usage scenario

  • Maintain and display the scenario of part overall relationship, such as tree menu, file and folder management.
  • A scenario in which some modules or functions can be separated from a whole.
  • As long as it is a tree structure, consider using a composite pattern.

structure

Component abstract component role: define common methods and properties of objects participating in the composition, and define some default behaviors or properties.

_ Leaf component:_ There is no other branch under the leaf object, that is, the smallest unit of traversal.

_ Composite branch component:_ Branch object, which combines branch nodes and leaf nodes to form a tree structure.

Code example

`public class Composite extends Component {`
 `//Component container`
 `private ArrayList<Component> componentArrayList = new`
 `ArrayList<Component>();`
 `//Add a leaf component or a branch component`
 `public void add(Component component){`
 `this.componentArrayList.add(component);`
 `}`
 `//Delete a leaf or branch component`
 `public void remove(Component component){`
 `this.componentArrayList.remove(component);`
 `}`
 `//Obtain all leaf and branch components under the branch`
 `public ArrayList<Component> getChildren(){`
 `return this.componentArrayList;`
 `}` 
`}`

Observer mode

concept

Define a one to many dependency between objects, so that whenever an object changes state, all objects that depend on it will be notified and updated automatically.

Usage scenario

  • Associate behavior scenarios. It should be noted that the association behavior is separable, not a "composite" relationship.
  • Event multi-level trigger scenario.
  • Cross system message exchange scenarios, such as the processing mechanism of message queue.

structure

_ Subject observed:_ Define the responsibilities that must be realized by the observed. It must be able to dynamically add and cancel observers. It is generally an abstract class or an implementation class, which only performs the duties that the observer must implement: managing the observer and notifying the observer.

_ Observer:_ After receiving the message, the observer performs an update operation to process the received information.

_ ConcreteSubject: specific observers:_ Define the observer's own business logic and what events to notify.

_ ConcreteObserver specific observers:_ The processing response of each observer after receiving the message is different, and each observer has its own processing logic.

Code example

`public abstract class Subject {`
 `//Define an array of observers`
 `private Vector<Observer> obsVector = new Vector<Observer>();`
 `//Add an observer`
 `public void addObserver(Observer o){`
 `this.obsVector.add(o);`
 `}`
 `//Delete an observer`
 `public void delObserver(Observer o){`
 `this.obsVector.remove(o);`
 `}`
 `//Notify all observers`
 `public void notifyObservers(){`
 `for(Observer o:this.obsVector){`
 `o.update();`
 `}`
 `}` 
`}`

Facade mode

concept

It is required that the external and internal communication of a subsystem must be carried out through a unified object. Facade mode provides a high-level interface, which makes the subsystem easier to use.

Usage scenario

  • Provide an external access interface for a complex module or subsystem
  • The subsystem is relatively independent - external access to the subsystem can only be operated in a black box
  • Prevent the risk spread caused by low-level personnel

structure

_ Facade facade role:_ The client can call the methods of this role. This role is aware of all functions and responsibilities of the subsystem. Generally, this role will delegate all requests sent from the client to the corresponding subsystem, that is, this role has no actual business logic, but is just a delegate class.

_ Subsystem subsystem role:_ There can be one or more subsystems at the same time. Each subsystem is not a separate class, but a collection of classes. The subsystem does not know the existence of the facade. For the subsystem, the facade is just another client.

Code mode

`public class Client {`
 `//Delegated subsystem object`
 `private A a= new A();`
 `private B b= new B();`
 `private C c= new C();`
 `//Methods for providing external access`
 `public void methodA(){`
 `this.a.doSomething();`
 `}`
 `public void methodB(){`
 `this.b.doSomething();`
 `}`
 `public void methodC(){`
 `this.c.doSomething();`
 `}`
`}`

Memo mode

concept

Without breaking the encapsulation, capture the internal state of an object and save the state outside the object. This will restore the object to its original saved state later.

Usage scenario

  • Relevant state scenarios that need to save and restore data.
  • Provides a rollback operation.
  • In the replica scenario that needs to be monitored.
  • The transaction management of database connection is the memo mode.

structure

_ Originator initiator role:_ Record the internal status at the current time, define the status within the backup scope, and create and restore memo data.

_ Memento memo role:_ It is responsible for storing the internal state of the Originator initiator object and providing the internal state required by the initiator when necessary.

_ Caretaker memo administrator role:_ Manage, save and provide memos.

Code example

`public class BeanUtils {`
 `//Put all the attributes and values of the bean , into the , Hashmap ,`
 `public static HashMap<String,Object> backupProp(Object bean){`
 `HashMap<String,Object> result = new`
 `HashMap<String,Object>();`
 `try {`
 `//Get Bean description`
 `BeanInfo`
 `beanInfo=Introspector.getBeanInfo(bean.getClass());`
 `//Get attribute description`
 `PropertyDescriptor[]`
 `descriptors=beanInfo.getPropertyDescriptors();`
 `//Traverse all attributes`
 `for(PropertyDescriptor des:descriptors){`
 `//Attribute name`
 `String fieldName = des.getName();`
 `//Method to read properties`
 `Method getter = des.getReadMethod();`
 `//Read attribute value`
 `Object fieldValue=getter.invoke(bean,new`
 `Object[]{});`
 `if(!fieldName.equalsIgnoreCase("class")){`
 `result.put(fieldName, fieldValue);`
 `} } } catch (Exception e) {`
 `//Exception handling`
 `}`
 `return result;`
 `}`
 `//Return the value of {HashMap} to {bean}`
 `public static void restoreProp(Object bean,HashMap<String,Object>`
 `propMap){`
 `try {`
 `//Get Bean description`
 `BeanInfo beanInfo =`
 `Introspector.getBeanInfo(bean.getClass());`
 `//Get attribute description`
 `PropertyDescriptor[] descriptors =`
 `beanInfo.getPropertyDescriptors();`
 `//Traverse all attributes`
 `for(PropertyDescriptor des:descriptors){`
 `//Attribute name`
 `String fieldName = des.getName();`
 `//If you have this attribute`
 `if(propMap.containsKey(fieldName)){`
 `//Method of writing attributes`
 `Method setter = des.getWriteMethod();`
 `setter.invoke(bean, new`
 `Object[]{propMap.get(fieldName)});`
 `} } } catch (Exception e) {`
 `//Exception handling`
 `System.out.println("shit");`
 `e.printStackTrace();`
 `}`
 `}`
`}`

Visitor mode

concept

Encapsulates some operations that act on each element in a data structure. It can define new operations that act on these elements without changing the data structure.

Usage scenario

  • An object structure contains many class objects, which have different interfaces, and you want to implement some operations on these objects that depend on their specific classes, that is to say, the iterator pattern is no longer competent.
  • You need to perform many different and irrelevant operations on objects in an object structure, and you want to avoid making these operations "pollute" the classes of these objects.

structure

_ Visitor - Abstract visitor:_ Abstract classes or interfaces declare which elements visitors can access. Specifically, the parameters of the visit method in the program define which objects can be accessed.

_ ConcreteVisitor - specific visitor:_ It affects what visitors should do and what they should do after accessing a class.

_ Element -- abstract element:_ Interface or abstract class, which declares which type of visitor to accept, is defined programmatically through the parameters in the accept method.

_ ConcreteElement -- concrete element:_ Implement the accept method, usually visitor Visit (this) has basically formed a model.

_ ObjectStruture -- structure object:_ The element generator is generally contained in multiple containers with different types and interfaces, such as List, Set, Map, etc. in the project, this role is rarely abstracted.

Code example

`public class CompensationVisitor implements Visitor {`
 `@Override`
 `public void Visit(Element element) {`
 `// TODO Auto-generated method stub`
 `Employee employee = ((Employee) element);`
 `System.out.println(`
 `employee.getName() + "'s Compensation is " + (employee.getDegree() * employee.getVacationDays() * 10));`
 `}`
`}`

State mode

concept

When an object's internal state changes, it is allowed to change its behavior, and the object looks like it has changed its class.

Usage scenario

  • This is also the fundamental starting point of the state mode. For example, the status of permission designers will be different even if they execute the same behavior. In this case, it is necessary to consider using the state mode.
  • Substitutes for conditional and branch judgment statements

structure

_ State - abstract state role:_ Interface or abstract class, which is responsible for defining the object state and encapsulating the environment role to realize state switching.

_ ConcreteState - specific state role:_ Each specific state must fulfill two responsibilities: the behavior management of this state and the processing of trend state. Generally speaking, it is what to do in this state and how to transition from this state to other states.

_ Context - environment role:_ Define the interface required by the client and be responsible for the switching of specific states.

Code example

`//Abstract state role`
`public abstract class State {`
 `//Define an environment role to provide subclass access`
 `protected Context context;`
 `//Setting environment roles`
 `public void setContext(Context _context){`
 `this.context = _context;`
 `}`
 `//Behavior 1`
 `public abstract void handle1();`
 `//Behavior 2`
 `public abstract void handle2();`
`}`

Interpreter mode

concept

Given a language, define a representation of its grammar and define an interpreter that uses the representation to interpret sentences in the language.

Usage scenario

  • The interpreter mode can be used for recurring problems
  • A simple syntax needs to be explained

structure

_ AbstractExpression -- Abstract interpreter:_ The specific interpretation task is completed by each implementation class, and the specific interpreter is completed by TerminalExpression and non TerminalExpression respectively.

_ TerminalExpression -- terminator expression:_ It implements the interpretation operation associated with the elements in the grammar. Usually, there is only one terminator expression in an interpreter mode, but there are multiple instances corresponding to different terminators.

_ NonterminalExpression -- non terminator expression:_ Each rule in grammar corresponds to a non terminal expression, which increases according to the complexity of logic. In principle, each grammar rule corresponds to a non terminal expression.

_ Context - environment role:_ It is generally used to store the specific values corresponding to each terminator in the grammar. This information needs to be stored in the environment role. In many cases, it is enough for us to use Map to act as the environment role.

Code example

`/**`
 `* Terminator expression`
 `*/`
`public class TerminalExpression extends AbstractExpression {`
 `@Override`
 `public void interpret(Context ctx) {`
 `//Implements the interpretation operation associated with the terminator in the syntax rule`
 `}`
`}`
`/**`
 `* Non terminator expression`
 `*/`
`public class NonterminalExpression extends AbstractExpression {`
 `@Override`
 `public void interpret(Context ctx) {`
 `//Implements interpretation operations associated with non terminators in syntax rules`
 `}`
`}`

Sharing element mode

concept

Using shared objects can effectively support a large number of fine-grained objects.

The information of an object is divided into two parts: internal state and external state.

_ Internal status:_ The internal state is the information that can be shared by the object. It is stored in the shared meta object and will not change with the environment.

_ External status:_ External state is a mark that objects can depend on. It is a state that changes with the environment and cannot be shared.

Usage scenario

  • There are a large number of similar objects in the system.
  • Fine grained objects have close external states, and the internal state is independent of the environment, that is, the object has no specific identity.
  • Scenarios that require buffer pools.

structure

_ Flyweight - Abstract meta role:_ It is simply an abstract class of a product, which defines the interface or implementation of the external state and internal state of the object at the same time.

_ ConcreteFlyweight - specific roles:_ A specific product class that implements the business defined by the abstract role. In this role, it should be noted that the internal state processing should be independent of the environment. There should be no operation that changes the internal state and modifies the external state. This is absolutely not allowed.


_ unsharedConcreteFlyweight -- unshareable meta roles:_ Objects with no external state or security requirements (such as thread safety) that cannot use sharing technology generally do not appear in the sharing factory.

_ FlyweightFactory - Xiangyuan factory:_ The responsibility is very simple. It is to construct a pool container and provide methods to get objects from the pool.

Code example

`public class FlyweightFactory {`
 `//Define a pool container`
 `private static HashMap<String,Flyweight> pool= new`
 `HashMap<String,Flyweight>();`
 `//Xiangyuan factory`
 `public static Flyweight getFlyweight(String Extrinsic){`
 `//Object to return`
 `Flyweight flyweight = null;`
 `//The object does not exist in the pool`
 `if(pool.containsKey(Extrinsic)){`
 `flyweight = pool.get(Extrinsic);`
 `}else{`
 `//Create meta objects based on external state`
 `flyweight = new ConcreteFlyweight1(Extrinsic);`
 `//Place in pool`
 `pool.put(Extrinsic, flyweight);`
 `}`
 `return flyweight;`
 `}`
`}`

Bridge mode

concept

Decouple abstraction and implementation so that they can change independently.

Usage scenario

  • Scenarios where inheritance is not desired or applicable
  • Scenarios where interfaces or abstract classes are unstable
  • Scenarios requiring high reusability

structure

_ Abstraction -- Abstract role:_ Its main responsibility is to define the behavior of the role and save a reference to the implemented role, which is generally an abstract class.

_ Implementor -- implementing roles:_ It is an interface or abstract class that defines the necessary behaviors and properties of a role.

_ RefinedAbstraction -- modify abstracted roles:_ It refers to the implementation role to modify the abstract role.

_ Concreteimplementer - concrete implementation role:_ It implements methods and properties defined by interfaces or abstract classes.

Code example

`public abstract class Abstraction {`
 `//Defines a reference to an implementation role`
 `private Implementor imp;`
 `//Constraint subclasses must implement this constructor`
 `public Abstraction(Implementor _imp){`
 `this.imp = _imp;`
 `}`
 `//Own behavior and attributes`
 `public void request(){`
 `this.imp.doSomething();`
 `}`
 `//Get realized roles`
 `public Implementor getImp(){`
 `return imp;`
 `}`
`}`

total

When you learn design patterns, don't look at how difficult it is. In the final analysis, it is an introductory summary. We need to understand its deep principle slowly in our daily continuous learning and work, so as to flexibly apply each design mode.

Design pattern is a solution to the problems of some scenes based on the summary of predecessors. Design pattern is not a formula. There is no need to memorize each pattern. More importantly, it is important to understand its abstract ideas, how to better solve problems by applying design patterns, and what effect can be achieved. Although there are many theories, if we want to master them, many problems will be solved for our practical development.

Of course, we will continue to update the content on design principles for you to further understand the design pattern

Keywords: Java Design Pattern Programmer

Added by robogenus on Wed, 15 Dec 2021 13:22:35 +0200