Design patterns (GOF) are divided into three types, a total of 23 categories.
1, Create mode:
Singleton pattern, abstract factory pattern, builder pattern, factory pattern, prototype pattern.
2, Structural mode:
Adapter mode, bridge mode, decoration mode, combination mode, appearance mode, sharing mode and agent mode.
3, Behavioral mode:
Template method mode, command mode, iterator mode, observer mode, mediator mode, memo mode, interpreter mode, state mode, policy mode, responsibility chain mode and visitor mode.
catalogue
1. Singleton mode
Ensure that a class has only one instance, and the class can create the instance itself and provide a global access point to access it. The singleton pattern is one of the simplest design patterns.
characteristic:
A singleton class has only one instance object;
The singleton object must be created by the singleton class itself;
The singleton class provides a global access point for accessing the singleton.
Advantages and disadvantages of singleton mode:
advantage:
The singleton mode can ensure that there is only one instance in the memory and reduce the memory consumption;
It can avoid multiple occupation of resources;
Set global access points in singleton mode to optimize and share resource access.
Disadvantages:
The singleton mode generally has no interface and is difficult to expand. If you want to expand, there is no second way except to modify the original code, which violates the opening and closing principle;
In concurrent testing, singleton mode is not conducive to code debugging. During debugging, if the code in the single instance is not executed completely, a new object cannot be simulated;
The function code of singleton mode is usually written in a class. If the function design is unreasonable, it is easy to violate the principle of single responsibility.
Application scenario of singleton mode:
For some classes that need to be created frequently, using singleton can reduce the memory pressure of the system and reduce GC (garbage collection);
When a class only requires to produce an object, such as a monitor in a class, the ID number of each person, etc.
Some classes occupy more resources when creating instances, or the instantiation takes a long time and is often used;
When a class needs frequent instantiation and the created objects are frequently destroyed, such as multi-threaded thread pool, network connection pool, etc;
Objects that frequently access databases or files;
For some control hardware level operations, or from the system point of view, they should be single control logic operations. If there are multiple instances, the system will be completely disordered;
When objects need to be shared. Since singleton mode allows only one object to be created, sharing the object can save memory and speed up object access. Such as the configuration object in the Web, the connection pool of the database, etc.
Implementation of singleton mode:
Lazy: the feature of this mode is that no singleton is generated during class loading. This singleton is created only when the getlnstance method is called for the first time. The code is as follows:
public class LazySingleton { private static volatile LazySingleton instance = null; //Ensure that instance is synchronized in all threads private LazySingleton() { } //private prevents classes from being instantiated externally public static synchronized LazySingleton getInstance() { //Add synchronization before getInstance method if (instance == null) { instance = new LazySingleton(); } return instance; } }
If you are writing a multithreaded program, do not delete the keywords volatile and synchronized in the above example code, otherwise there will be a thread unsafe problem. If you do not delete these two keywords, you can ensure thread safety, but you have to synchronize each access, which will affect performance and consume more resources. This is the disadvantage of lazy singleton.
Hungry Chinese style: the feature of this mode is that once the class is loaded, a singleton is created to ensure that the singleton already exists before calling the getInstance method.
public class HungrySingleton { private static final HungrySingleton instance = new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getInstance() { return instance; } }
Hungry Chinese singleton has created a static object for the system to use at the same time as the class is created, which will not be changed in the future. Therefore, it is thread safe and can be directly used for multithreading without problems.
2. Prototype
Use the prototype instance to specify the type of object to be created, and copy the prototype to create a new object that is the same or similar to the prototype.
Advantages and disadvantages of prototype:
advantage:
The built-in prototype mode 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:
You need to configure a clone method for each class;
clone method is located inside the class. When modifying an existing class, the code needs to be modified, 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.
Structure of mode:
The prototype pattern contains the following main roles:
Abstract prototype class: Specifies the interface that the concrete prototype object must implement.
Concrete prototype class: implement the clone() method of the Abstract prototype class, which is an object that can be copied.
Access class: use the clone() method in the concrete prototype class to copy the new object.
Implementation of mode:
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.
The Object class in Java provides the clone() method of shallow cloning. The specific prototype class can realize the shallow cloning of objects as long as it implements the clonable interface, which is an abstract prototype class. Its code is as follows:
//Concrete prototype class class Realizetype implements Cloneable { Realizetype() { System.out.println("The specific prototype was created successfully!"); } public Object clone() throws CloneNotSupportedException { System.out.println("Specific prototype copied successfully!"); return (Realizetype) super.clone(); } } //Prototype pattern test class public class PrototypeTest { public static void main(String[] args) throws CloneNotSupportedException { Realizetype obj1 = new Realizetype(); Realizetype obj2 = (Realizetype) obj1.clone(); System.out.println("obj1==obj2?" + (obj1 == obj2)); } }
Simple factory mode
Define a factory class, which can return different instances according to different parameters. The created instances usually have a common parent class. (it does not belong to the 23 modes)
Advantages and disadvantages of simple factory:
advantage:
The factory class contains the necessary logical judgment to decide when to create an instance of which product. The client can avoid the responsibility of directly creating product objects and easily create corresponding products. The responsibilities of the factory and products are clearly distinguished.
The client does not need to know the class name of the specific product created, but only needs to know the parameters.
You can also import a configuration file to replace and add new specific product classes without modifying the client code.
Disadvantages:
The factory class of simple factory mode is single, which is responsible for the creation of all products. The responsibility is too heavy. Once it is abnormal, the whole system will be affected. Moreover, the factory class code will be very bloated and violate the principle of high aggregation.
Using simple factory mode will increase the number of classes in the system (introduce new factory classes), increase the complexity and understanding difficulty of the system.
It is difficult to expand the system. Once new products are added, the factory logic has to be modified. When there are many product types, the logic may be too complex.
The simple factory mode uses the static factory method, which makes the factory role unable to form an inheritance based hierarchical structure.
Structure and implementation of simple factory mode:
The main roles of the simple factory model are as follows:
Simple factory: it is the core of the simple factory pattern and is responsible for implementing the internal logic of creating all instances. The method of creating product class of factory class can be directly called by the outside world to create the required product object.
Abstract Product: it is the parent class of all objects created by a simple factory and is responsible for describing the common interface shared by all instances.
Concrete product: it is the creation target of simple factory mode.
Reference codes are as follows:
public class Client { public static void main(String[] args) { } //Abstract product public interface Product { void show(); } //Specific product: ProductA static class ConcreteProduct1 implements Product { public void show() { System.out.println("Specific product 1 display..."); } } //Specific product: ProductB static class ConcreteProduct2 implements Product { public void show() { System.out.println("Specific product 2 display..."); } } final class Const { static final int PRODUCT_A = 0; static final int PRODUCT_B = 1; static final int PRODUCT_C = 2; } static class SimpleFactory { public static Product makeProduct(int kind) { switch (kind) { case Const.PRODUCT_A: return new ConcreteProduct1(); case Const.PRODUCT_B: return new ConcreteProduct2(); } return null; } } }
3. Factory Method
Define an interface for creating objects and let subclasses decide which class to instantiate. Factory Method delays the instantiation of a class to its subclasses.
Advantages and disadvantages of the mode:
advantage:
Users only need to know the name of the specific factory to get the desired product, without knowing the specific creation process of the product;
The flexibility is enhanced. For the creation of new products, you only need to write one more corresponding factory class;
Typical decoupling framework. The high-level module only needs to know the abstract class of the product, does not need to care about other implementation classes, and meets the Demeter rule, dependency inversion principle and Richter substitution principle.
Disadvantages:
The number of classes is easy to be too many, which increases the complexity;
It increases the abstraction and understanding difficulty of the system;
Abstract products can only produce one product, which can be solved by using abstract factory mode.
Structure of mode:
The main roles of the factory method model are as follows:
Abstract Factory: it provides an interface for creating products, through which the caller accesses the factory method newProduct() of a specific factory to create products;
Concrete factory: it mainly realizes the abstract methods in the abstract factory and completes the creation of specific products;
Abstract Product: it defines the Product specification and describes the main characteristics and functions of the Product;
Concrete product: it implements the interface defined by the abstract product role, which is created by the specific factory and corresponds to the specific factory one by one.
Specific code implementation reference online.
4. Abstract Factory pattern
It is a pattern structure that provides an interface for the access class to create a group of related or interdependent objects, and the access class can obtain different levels of products of the same family without specifying the specific class of the product.
Advantages and disadvantages of abstract factory pattern:
In addition to the advantages of the factory method pattern, the abstract factory pattern has the following main advantages.
The multi-level products associated in the product family can be managed together within the class, instead of introducing multiple new classes for management.
When a product family is required, the abstract factory can ensure that the client always uses only the product group of the same product.
Abstract factory enhances the scalability of the program. When adding a new product family, there is no need to modify the original code to meet the opening and closing principle.
The disadvantage is that when a new product needs to be added to the product family, all factory classes need to be modified. It increases the abstraction and understanding difficulty of the system.
Structure of mode:
The main roles of the abstract factory pattern are as follows.
Abstract Factory: it provides an interface for creating products. It contains multiple methods for creating products newProduct(), which can create multiple products of different levels.
Concrete Factory: it mainly implements multiple abstract methods in the abstract factory to complete the creation of specific products.
Abstract Product: it defines the Product specification and describes the main features and functions of the Product. The abstract factory pattern has multiple Abstract products.
Concrete product: it implements the interface defined by the abstract product role and is created by the concrete factory. It has a many-to-one relationship with the concrete factory.
Implementation of mode:
(1) Abstract factory: provides the generation method of products.
interface AbstractFactory { public Product1 newProduct1(); public Product2 newProduct2(); }
(2) Specific factory: the product generation method is realized.
class ConcreteFactory1 implements AbstractFactory { public Product1 newProduct1() { System.out.println("Specific factory 1 generation-->Specific products 11..."); return new ConcreteProduct11(); } public Product2 newProduct2() { System.out.println("Specific factory 1 generation-->Specific products 21..."); return new ConcreteProduct21(); } }
5. Builder mode (builder)
It refers to separating the construction of a complex object from its representation, so that the same construction process can create different representations. It decomposes a complex object into several simple objects, and then builds them step by step. It separates change from invariance, that is, the components of the product are invariable, but each part can be flexibly selected.
Advantages and disadvantages of the mode:
advantage:
Good encapsulation, separation of construction and representation;
Good expansibility, each specific builder is independent of each other, which is conducive to the decoupling of the system;
The client does not need to know the details of the internal composition of the product. The builder can gradually refine the creation process without any impact on other modules, so as to control the detail risk.
Disadvantages:
The components of the product must be the same, which limits its scope of use.
If the internal changes of the product are complex, if the internal changes of the product occur, the builder should also modify them synchronously, and the later maintenance cost is large.
Structure of mode:
The main roles of the Builder pattern are as follows.
Product role: it is a complex object containing multiple components, and its components are created by specific builders;
Abstract Builder: it is an interface that contains abstract methods for creating various sub parts of a product, and usually includes a method getResult(), which returns a complex product;
Concrete Builder: implement the builder interface and complete the specific creation method of various components of complex products;
Director: it calls the component construction and assembly methods in the builder object to complete the creation of complex objects. The director does not involve the information of specific products.
Implementation of mode:
(1) Product roles: complex objects that contain multiple components.
class Product { private String partA; private String partB; private String partC; public void setPartA(String partA) { this.partA = partA; } public void setPartB(String partB) { this.partB = partB; } public void setPartC(String partC) { this.partC = partC; } public void show() { //Displays the characteristics of the product } }
(2) Abstract Builder: contains the abstract method of creating each sub part of the product.
abstract class Builder { //Create product object protected Product product = new Product(); public abstract void buildPartA(); public abstract void buildPartB(); public abstract void buildPartC(); //Return product object public Product getResult() { return product; } }
(3) Concrete Builder: implements the abstract builder interface.
public class ConcreteBuilder extends Builder { public void buildPartA() { product.setPartA("build PartA"); } public void buildPartB() { product.setPartB("build PartB"); } public void buildPartC() { product.setPartC("build PartC"); } }
(4) Commander: call the method in the builder to complete the creation of complex objects.
class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } //Product construction and assembly method public Product construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } }
(5) Customer class.
public class Client { public static void main(String[] args) { Builder builder = new ConcreteBuilder(); Director director = new Director(builder); Product product = director.construct(); product.show(); } }
The builder mode is mainly applicable to the following application scenarios:
The same method and different execution order produce different results;
Multiple components or parts can be assembled into one object, but the results are different;
The product class is very complex, or different call sequences in the product class have different effects;
Initializing an object is particularly complex, with many parameters, and many parameters have default values.
Difference between builder mode and factory mode:
The builder mode pays more attention to the calling sequence of methods, and the factory mode pays more attention to the creation of objects;
The intensity of creating objects is different. The builder mode creates complex objects, which are composed of various complex components. The objects created by the factory mode are the same;
The focus is different. The factory mode only needs to create the object, while the builder mode not only needs to create the object, but also needs to know what components the object is composed of;
The builder mode is different according to the order of the construction process, and the composition of the final object components is also different.
6. Proxy mode (proxy)
Provide a proxy for other objects to control access to this object.
Advantages and disadvantages of the mode:
advantage:
Proxy mode plays an intermediary role between the client and the target object and protects the target object;
The proxy object can extend the function of the target object;
Proxy mode can separate the client from the target object, reduce the coupling of the system to a certain extent, and increase the scalability of the program.
Disadvantages (the disadvantages can be solved by dynamic agent):
The agent pattern will increase the number of classes in the system design
Adding a proxy object between the client and the target object will slow down the request processing speed;
It increases the complexity of the system.
Structure of mode:
The main roles of the agent model are as follows.
Abstract Subject class: declare business methods implemented by real subjects and proxy objects through interfaces or abstract classes;
Real Subject class: it implements the specific business in the abstract subject. It is the real object represented by the proxy object and the object to be referenced finally;
Proxy class: it provides the same interface as the real topic. It contains references to the real topic. It can access, control or extend the functions of the real topic.
According to the creation period of the agent, the agent mode is divided into static agent and dynamic agent.
Static: the programmer creates an agent class or a specific tool automatically generates the source code and compiles it. The. Class file of the agent class already exists before the program runs.
Dynamic: it is created dynamically by using reflection mechanism when the program is running.
Implementation of mode:
public class ProxyTest { public static void main(String[] args) { Proxy proxy = new Proxy(); proxy.Request(); } } //Abstract theme interface Subject { void Request(); } //Real theme class RealSubject implements Subject { public void Request() { System.out.println("How to access real topics..."); } } //agent class Proxy implements Subject { private RealSubject realSubject; public void Request() { if (realSubject == null) { realSubject = new RealSubject(); } preRequest(); realSubject.Request(); postRequest(); } public void preRequest() { System.out.println("Preprocessing before accessing a real topic."); } public void postRequest() { System.out.println("Subsequent processing after accessing the real topic."); } }
7. Adapter mode
Convert the interface of a class into another interface that customers want. The Adapter mode enables those classes that cannot work together due to incompatible interfaces to work together. The Adapter mode is divided into class structure mode and object structure mode. The former has higher coupling between classes than the latter, and requires programmers to understand the internal structure of relevant components in the existing component library Structure, so the application is relatively less.
Advantages and disadvantages of the mode:
advantage:
The client can call the target interface transparently through the adapter;
Reusing the existing classes, programmers do not need to modify the original code and reuse the existing adapter classes;
Decoupling the target class from the adapter class solves the problem of inconsistent interfaces between the target class and the adapter class;
In many business scenarios, it conforms to the opening and closing principle.
Disadvantages:
The adapter writing process needs to be comprehensively considered in combination with the business scenario, which may increase the complexity of the system;
Increase the difficulty of code reading and reduce the readability of code. Excessive use of adapters will make the system code messy.
Structure of mode:
Class adapter mode can be implemented by multiple inheritance, such as C + + interface; Java does not support multi inheritance, but you can define an adapter class to implement the business interface of the current system and inherit the existing components in the existing component library.
The object adapter mode can introduce the implemented components in the existing component library into the adapter class, which also implements the business interface of the current system.
The Adapter pattern contains the following main roles.
Target interface: the interface expected by the current system business, which can be an abstract class or interface;
Adapter class: it is the component interface in the existing component library accessed and adapted;
Adapter class: it is a converter that converts the adapter interface into a target interface by inheriting or referencing the adapter object, so that customers can access the adapter in the format of the target interface.
Implementation of mode:
(1) The code of class adapter pattern is as follows.
package adapter; //Target interface interface Target { public void request(); } //Adapter interface class Adaptee { public void specificRequest() { System.out.println("The business code in the adapter is called!"); } } //Class adapter class class ClassAdapter extends Adaptee implements Target { public void request() { specificRequest(); } } //Client code public class ClassAdapterTest { public static void main(String[] args) { System.out.println("Class adapter mode test:"); Target target = new ClassAdapter(); target.request(); } }
(2) The code for the object adapter pattern is as follows.
package adapter; //Object adapter class class ObjectAdapter implements Target { private Adaptee adaptee; public ObjectAdapter(Adaptee adaptee) { this.adaptee=adaptee; } public void request() { adaptee.specificRequest(); } } //Client code public class ObjectAdapterTest { public static void main(String[] args) { System.out.println("Object adapter mode test:"); Adaptee adaptee = new Adaptee(); Target target = new ObjectAdapter(adaptee); target.request(); } }
Note: the codes of "target interface" and "adapter class" in the object adapter mode are the same as those in the same adapter mode. Just modify the adapter class and client code.
8. Bridge mode
Separate the abstract part from its implementation part so that they can change independently. It is implemented by replacing inheritance relationship with composition relationship, which reduces the coupling between abstraction and implementation.
Advantages and disadvantages of the mode:
advantage:
Separation of abstraction and implementation, strong scalability;
Comply with the opening and closing principle;
Comply with the principle of synthetic reuse;
Its implementation details are transparent to customers.
Disadvantages:
Because the aggregation relationship is based on the abstraction layer, developers are required to design and program for abstraction, and can correctly identify two independent changing dimensions in the system, which increases the difficulty of system understanding and design.
Structure of mode:
The Bridge mode contains the following main roles.
Abstraction role: defines an abstract class and contains a reference to the implementation object;
Refined Abstraction role: it is a subclass of the abstract role, implements the business methods in the parent class, and calls the business methods in the abstract role through the composition relationship;
Implementer role: defines the interface of the implementer role, which can be called by the extended abstract role;
Concrete implementer role: give the concrete implementation of the implementation role interface.
Implementation of mode:
package bridge; public class BridgeTest { public static void main(String[] args) { Implementor imple = new ConcreteImplementorA(); Abstraction abs = new RefinedAbstraction(imple); abs.Operation(); } } //Realize role interface Implementor { public void OperationImpl(); } //Concrete implementation role class ConcreteImplementorA implements Implementor { public void OperationImpl() { System.out.println("Concrete realization(Concrete Implementor)Role is accessed"); } } //Abstract role abstract class Abstraction { protected Implementor imple; protected Abstraction(Implementor imple) { this.imple = imple; } public abstract void Operation(); } //Extended abstract role class RefinedAbstraction extends Abstraction { protected RefinedAbstraction(Implementor imple) { super(imple); } public void Operation() { System.out.println("Extended abstraction(Refined Abstraction)Role is accessed"); imple.OperationImpl(); } }
9. Decorator mode
It refers to the mode of dynamically adding some responsibilities (i.e. adding additional functions) to the object without changing the existing object structure.
Advantages and disadvantages of the mode:
advantage:
Decorator is a powerful supplement to inheritance, which is more flexible than inheritance. It dynamically extends the function of an object without changing the original object, plug and play;
Different effects can be achieved by using different decorative classes and the arrangement and combination of these decorative classes;
The decorator mode fully complies with the opening and closing principle.
Disadvantages: decorator pattern will add many subclasses, and overuse will increase the complexity of the program.
Structure of mode:
Decorator mode mainly includes the following roles.
Abstract Component role: define an abstract interface to standardize objects ready to receive additional responsibilities;
Concrete component role: implement abstract components and add some responsibilities to them through decorative roles;
Abstract Decorator role: it inherits abstract components and contains instances of specific components, and can extend the functions of specific components through its subclasses;
Concrete decorator role: implement relevant methods of abstract decoration and add additional responsibilities to specific component objects.
Implementation of mode:
package decorator; public class DecoratorPattern { public static void main(String[] args) { Component p = new ConcreteComponent(); p.operation(); System.out.println("---------------------------------"); Component d = new ConcreteDecorator(p); d.operation(); } } //Abstract component role interface Component { public void operation(); } //Specific component role class ConcreteComponent implements Component { public ConcreteComponent() { System.out.println("Create concrete component roles"); } public void operation() { System.out.println("Calling methods for specific component roles operation()"); } } //Abstract decorative role class Decorator implements Component { private Component component; public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); } } //Specific decorative role class ConcreteDecorator extends Decorator { public ConcreteDecorator(Component component) { super(component); } public void operation() { super.operation(); addedFunction(); } public void addedFunction() { System.out.println("Add additional functions to specific component roles addedFunction()"); } }
10. Appearance mode (Facade)
It is a mode that makes these subsystems more accessible by providing a consistent interface for multiple complex subsystems. This mode has a unified interface to the outside, and the external application does not care about the specific details of the internal subsystem, which will greatly reduce the complexity of the application and improve the maintainability of the program
Advantages and disadvantages of the mode:
The Facade mode is a typical application of "Demeter's law", which has the following main advantages:
The coupling between the subsystem and the client is reduced, so that the change of the subsystem will not affect the client class calling it;
Shielding subsystem components from customers, reducing the number of objects handled by customers, and making the subsystem easier to use;
It reduces the compilation dependency in large software systems and simplifies the migration process of the system between different platforms, because compiling a subsystem will not affect other subsystems or appearance objects.
The main disadvantages are as follows:
It can not well restrict customers from using subsystem classes, which is easy to bring unknown risks;
Adding a new subsystem may require modifying the appearance class or the source code of the client, which violates the "opening and closing principle".
Structure of mode:
The structure of Facade pattern is relatively simple. It mainly defines a high-level interface. It contains references to each subsystem, through which clients can access the functions of each subsystem.
The Facade mode contains the following main roles.
Facade role: provide a common interface for multiple subsystems;
Sub System role: realize some functions of the system, and customers can access it through appearance role;
Client role: access the functions of each subsystem through one appearance role.
Implementation of mode:
package facade; public class FacadePattern { public static void main(String[] args) { Facade f = new Facade(); f.method(); } } //Appearance role class Facade { private SubSystem01 obj1 = new SubSystem01(); private SubSystem02 obj2 = new SubSystem02(); private SubSystem03 obj3 = new SubSystem03(); public void method() { obj1.method1(); obj2.method2(); obj3.method3(); } } //Subsystem roles class SubSystem01 { public void method1() { System.out.println("Of subsystem 01 method1()Called!"); } } //Subsystem roles class SubSystem02 { public void method2() { System.out.println("Of subsystem 02 method2()Called!"); } } //Subsystem roles class SubSystem03 { public void method3() { System.out.println("Of subsystem 03 method3()Called!"); } }
11. Flyweight mode
Sharing technology is used to effectively support the reuse of a large number of fine-grained objects. By sharing existing objects, it can greatly reduce the number of objects to be created and avoid the overhead of a large number of similar classes, so as to improve the utilization of system resources.
Advantages and disadvantages of the mode:
The advantages are:
Only one copy of the same object is saved, which reduces the number of objects in the system, thus reducing the pressure on memory caused by fine-grained objects in the system.
The disadvantages are:
In order to share objects, it is necessary to externalize some states that cannot be shared, which will increase the complexity of the program;
Reading the external state of the shared mode will make the running time slightly longer.
Structure of mode:
The definition of shared meta pattern puts forward two requirements, fine granularity and shared object. Because fine granularity is required, it is inevitable that there will be a large number of objects with similar properties. At this time, we will divide the information of these objects into two parts: internal state and external state.
Internal state refers to the information shared by the object, which is stored in the shared meta information and does not change with the change of the environment;
External state refers to a mark that an object can rely on. It changes with the change of environment and cannot be shared.
The essence of meta sharing mode is to cache shared objects and reduce memory consumption
The main roles of Xiangyuan mode are as follows:
Abstract shared element role (Flyweight): it is the base class of all specific shared element classes. It is the public interface to be implemented by the specific shared element specification. The external state of non shared elements is passed in the form of parameters through methods;
Concrete Flyweight role: implement the interface specified in the abstract flyweight role;
Unsharable flyweight role: it is an external state that cannot be shared. It is injected into the relevant methods of specific shared elements in the form of parameters;
Flyweight Factory role: it is responsible for creating and managing a membership role. When a client object requests a membership object, the membership factory checks whether there is a qualified membership object in the system. If so, it will provide it to the client; if not, it will create a new membership object.
Implementation of mode:
public class FlyweightPattern { public static void main(String[] args) { FlyweightFactory factory = new FlyweightFactory(); Flyweight f01 = factory.getFlyweight("a"); Flyweight f02 = factory.getFlyweight("a"); Flyweight f03 = factory.getFlyweight("a"); Flyweight f11 = factory.getFlyweight("b"); Flyweight f12 = factory.getFlyweight("b"); f01.operation(new UnsharedConcreteFlyweight("First call a. ")); f02.operation(new UnsharedConcreteFlyweight("Second call a. ")); f03.operation(new UnsharedConcreteFlyweight("3rd call a. ")); f11.operation(new UnsharedConcreteFlyweight("First call b. ")); f12.operation(new UnsharedConcreteFlyweight("Second call b. ")); } } //Non meta role class UnsharedConcreteFlyweight { private String info; UnsharedConcreteFlyweight(String info) { this.info = info; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } } //Abstract meta role interface Flyweight { public void operation(UnsharedConcreteFlyweight state); } //Specific meta role class ConcreteFlyweight implements Flyweight { private String key; ConcreteFlyweight(String key) { this.key = key; System.out.println("Specific share yuan" + key + "Created!"); } public void operation(UnsharedConcreteFlyweight outState) { System.out.print("Specific share yuan" + key + "Called,"); System.out.println("Non shared meta information is:" + outState.getInfo()); } } //Enjoy yuan factory role class FlyweightFactory { private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>(); public Flyweight getFlyweight(String key) { Flyweight flyweight = (Flyweight) flyweights.get(key); if (flyweight != null) { System.out.println("Specific share yuan" + key + "It already exists and was successfully obtained!"); } else { flyweight = new ConcreteFlyweight(key); flyweights.put(key, flyweight); } return flyweight; } }
12. Composite mode
Combine objects into a tree structure to represent a "part whole" hierarchy. It makes customers use single objects and composite objects consistently.
Advantages and disadvantages of the mode:
The advantages are:
The combination mode enables the client code to deal with single objects and combined objects consistently without caring whether they are dealing with single objects or combined objects, which simplifies the client code;
It is easier to add new objects to the assembly, and the client will not change the source code because of the addition of new objects, meeting the "opening and closing principle";
The disadvantages are:
The design is complex, and the client needs to spend more time to clarify the hierarchical relationship between classes;
It is not easy to limit the components in the container;
It is not easy to add new functions of components by inheritance;
Structure of mode:
The composite mode contains the following main roles:
Abstract Component role: its main role is to declare public interfaces for leaf components and branch components and implement their default behavior. In transparent composition mode, abstract components also declare interfaces for accessing and managing subclasses; in secure composition mode, interfaces for accessing and managing subclasses are not declared, and the management work is completed by branch components. (general abstract classes or interfaces, defining some general methods, such as adding and deleting);
Leaf component role: it is a leaf node object in the composition. It has no child nodes and is used to inherit or implement abstract components;
Composite role / intermediate component: it is a branch node object in the composition. It has child nodes, which are used to inherit and implement abstract components. Its main function is to store and manage child components, usually including Add(), Remove(), GetChild(), etc.
The combination mode is divided into transparent combination mode and safe combination mode.
Implementation of mode:
Transparent combination mode
public class CompositePattern { public static void main(String[] args) { Component c0 = new Composite(); Component c1 = new Composite(); Component leaf1 = new Leaf("1"); Component leaf2 = new Leaf("2"); Component leaf3 = new Leaf("3"); c0.add(leaf1); c0.add(c1); c1.add(leaf2); c1.add(leaf3); c0.operation(); } } //Abstract component interface Component { public void add(Component c); public void remove(Component c); public Component getChild(int i); public void operation(); } //Leaf component class Leaf implements Component { private String name; public Leaf(String name) { this.name = name; } public void add(Component c) { } public void remove(Component c) { } public Component getChild(int i) { return null; } public void operation() { System.out.println("leaf" + name + ": Be visited!"); } } //Branch member class Composite implements Component { private ArrayList<Component> children = new ArrayList<Component>(); public void add(Component c) { children.add(c); } public void remove(Component c) { children.remove(c); } public Component getChild(int i) { return children.get(i); } public void operation() { for (Object obj : children) { ((Component) obj).operation(); } } }
Safe combination mode
The implementation code of the secure composite mode is similar to that of the transparent composite mode. You can simply modify it. The code is as follows:
First, modify the Component code to preserve only the public behavior of the hierarchy.
interface Component { public void operation(); }
Then modify the client code and change the branch component type to Composite type to get the method to manage the subclass operation.
public class CompositePattern { public static void main(String[] args) { Composite c0 = new Composite(); Composite c1 = new Composite(); Component leaf1 = new Leaf("1"); Component leaf2 = new Leaf("2"); Component leaf3 = new Leaf("3"); c0.add(leaf1); c0.add(c1); c1.add(leaf2); c1.add(leaf3); c0.operation(); } }
13. Template Method
Define the skeleton of an algorithm in an operation and delay some steps to subclasses. Template Method enables subclasses to redefine some specific steps of an algorithm without changing the structure of the algorithm.
Advantages and disadvantages of the mode:
advantage:
It encapsulates the invariant part and extends the variable part. It encapsulates the algorithm that is considered to be the invariant part into the parent class, and inherits the variable part algorithm from the subclass, so that the subclass can continue to expand.
It extracts part of the common code from the parent class to facilitate code reuse.
Some methods are implemented by subclasses, so subclasses can add corresponding functions through extension, which conforms to the opening and closing principle.
Disadvantages:
For each different implementation, a subclass needs to be defined, which will increase the number of classes, make the system larger and more abstract, and indirectly increase the complexity of the system implementation.
Abstract methods in the parent class are implemented by subclasses. The structure executed by subclasses will affect the results of the parent class, which leads to a reverse control structure, which improves the difficulty of code reading.
Due to the shortcomings of the inheritance relationship itself, if a new abstract method is added to the parent class, all subclasses must be changed again.
Structure of mode:
The template method pattern needs to pay attention to the cooperation between abstract classes and concrete subclasses. It uses the polymorphism technology of virtual functions and the reverse control technology of "don't call me, let me call you".
The template method pattern contains the following main roles:
1) Abstract Class / Abstract Class
Abstract template class, which is responsible for giving the outline and skeleton of an algorithm. It consists of a template method and several basic methods. These methods are defined as follows:
Template method: defines the skeleton of the algorithm and calls its basic methods in a certain order;
Basic method: it is a step in the whole algorithm, including the following types:
Abstract method: declared in an abstract class and implemented by a concrete subclass;
Concrete method: it has been implemented in an abstract class and can be inherited or overridden in a concrete subclass;
Hook method: it has been implemented in abstract classes, including logical methods for judgment and empty methods that need to be overridden by subclasses
2) Concrete Class
The concrete implementation class implements the abstract methods and hook methods defined in the abstract class, which are a constituent step of a top-level logic.
Implementation of mode:
public class TemplateMethodPattern { public static void main(String[] args) { AbstractClass tm = new ConcreteClass(); tm.TemplateMethod(); } } //abstract class abstract class AbstractClass { //Template method public void TemplateMethod() { SpecificMethod(); abstractMethod1(); abstractMethod2(); } //Specific method public void SpecificMethod() { System.out.println("Concrete methods in abstract classes are called..."); } //Abstract method 1 public abstract void abstractMethod1(); //Abstract method 2 public abstract void abstractMethod2(); } //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..."); } }
14. Strategy
Define a series of algorithms, encapsulate them one by one, and make them replaceable, and the change of the algorithm will not affect the customers using the algorithm. This mode makes the changes of the algorithm independent of the customers using it.
Advantages and disadvantages of the mode:
The main advantages are as follows:
Multiple conditional statements are difficult to maintain, and the use of policy mode can avoid the use of multiple conditional statements, such as if...else statements and switch...case statements;
The policy pattern provides a series of reusable algorithm families. The proper use of inheritance can transfer the public code of the algorithm family to the parent class, so as to avoid duplicate code;
The policy mode can provide different implementations of the same behavior, and customers can choose different strategies according to different time or space requirements;
The strategy mode provides perfect support for the opening and closing principle, and can flexibly add new algorithms without modifying the original code;
The policy pattern puts the use of the algorithm into the environment class, and the implementation of the algorithm is moved to the specific policy class, which realizes the separation of the two.
The main disadvantages are as follows:
The client must understand the differences between all policy algorithms in order to select the appropriate algorithm class in time;
The policy mode creates many policy classes, which increases the difficulty of maintenance.
Structure of mode:
The policy pattern is to prepare a set of algorithms and encapsulate them into a series of policy classes as a subclass of an abstract policy class. The focus of policy mode is not how to implement algorithms, but how to organize these algorithms, so as to make the program structure more flexible, more maintainable and extensible. Now let's analyze its basic structure and implementation method.
The main roles of the policy mode are as follows:
Abstract Strategy class: defines a public interface. Different algorithms implement this interface in different ways. Environmental roles use this interface to call different algorithms, which are generally implemented by interfaces or abstract classes;
Concrete Strategy class: implements the interface of abstract policy definition and provides specific algorithm implementation;
Context class: holds a reference to a policy class, which is finally called to the client.
Implementation of mode:
public class StrategyPattern { public static void main(String[] args) { Context c = new Context(); Strategy s = new ConcreteStrategyA(); c.setStrategy(s); c.strategyMethod(); System.out.println("-----------------"); s = new ConcreteStrategyB(); c.setStrategy(s); c.strategyMethod(); } } //Abstract policy class interface Strategy { public void strategyMethod(); //Strategy method } //Specific strategy class A class ConcreteStrategyA implements Strategy { public void strategyMethod() { System.out.println("Specific strategies A The policy method of is accessed!"); } } //Specific strategy class B class ConcreteStrategyB implements Strategy { public void strategyMethod() { System.out.println("Specific strategies B The policy method of is accessed!"); } } //Environment class class Context { private Strategy strategy; public Strategy getStrategy() { return strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void strategyMethod() { strategy.strategyMethod(); } }
15. Command mode (command)
Encapsulate a request as an object, so that you can parameterize the customer with different requests; Queue or log requests, and support cancelable operations. In this way, the two communicate through the command object, which is convenient to store, transfer, call, add and manage the command object.
Advantages and disadvantages of the mode:
The main advantages are as follows:
Reduce the coupling degree of the system by introducing middleware (abstract interface);
It has good expansibility and is very convenient to add or delete commands. Using the command mode, adding and deleting commands will not affect other classes, and meet the "opening and closing principle";
Macro commands can be implemented. The command mode can be combined with the combined mode to assemble multiple commands into a combined command, that is, macro command;
It is convenient to realize Undo and Redo operations. The command mode can be combined with the memo mode introduced later to realize command revocation and recovery;
You can add additional functions to existing commands. For example, logging, combined with decorator mode, will be more flexible.
Its disadvantages are:
A large number of specific command classes may be generated. Because each specific operation needs to design a specific command class, which will increase the complexity of the system;
The result of the command mode is actually the execution result of the receiver. However, in order to structure and decouple the request and implementation in the form of command, additional type structure (the interface between the requester and abstract command) is introduced, which increases the difficulty of understanding. However, this is also a common problem of design patterns. Abstraction will inevitably increase the number of classes. Code separation must be more difficult to understand than code aggregation.
Structure of mode:
Relevant operations in the system can be abstracted into commands to separate the caller from the implementer.
The command mode contains the following main roles:
Abstract Command class (Command) role: it declares the interface for executing commands and has the abstract method execute();
Concrete Command role: it is the concrete implementation class of the abstract command class. It has the receiver object and completes the operation to be executed by calling the receiver's function;
Implementer / Receiver role: performs operations related to command functions and is the real implementer of specific command object business;
Caller / requester role: it is the sender of a request. It usually has many command objects and executes related requests by accessing the command object. It does not directly access the receiver.
Implementation of mode:
package command; public class CommandPattern { public static void main(String[] args) { Command cmd = new ConcreteCommand(); Invoker ir = new Invoker(cmd); System.out.println("Customer access caller's call()method..."); ir.call(); } } //caller class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void setCommand(Command command) { this.command = command; } public void call() { System.out.println("The caller executes the command command..."); command.execute(); } } //Abstract command interface Command { public abstract void execute(); } //order of the day class ConcreteCommand implements Command { private Receiver receiver; ConcreteCommand() { receiver = new Receiver(); } public void execute() { receiver.action(); } } //recipient class Receiver { public void action() { System.out.println("Recipient's action()Method called..."); } }
16. Chain of Responsibility
In order to decouple the sender and receiver of the request, multiple objects have the opportunity to process the request. Connect these objects into a chain and pass the request along the chain until an object processes it.
Advantages and disadvantages of the mode:
advantage:
Reduces the coupling between objects. In this mode, an object does not need to know which object handles its request and the structure of the chain, and the sender and receiver do not need to have the clear information of the other party;
It enhances the scalability of the system. New request processing classes can be added as needed to meet the opening and closing principle;
Increased flexibility in assigning responsibilities to objects. When the workflow changes, you can dynamically change the members in the chain or transfer their order, or dynamically add or delete responsibilities;
The chain of responsibility simplifies the connection between objects. Each object only needs to maintain a reference to its successor without maintaining the references of all other processors, which avoids the use of many if or if ·· else statements;
Responsibility sharing. Each class only needs to deal with its own work that should be handled, and the work that should not be handled should be transferred to the next object for completion. The scope of responsibility of each class should be defined and in line with the principle of single responsibility of the class.
Disadvantages:
There is no guarantee that every request will be processed. Since a request has no specific receiver, it cannot be guaranteed that it will be processed. The request may not be processed until it reaches the end of the chain;
For a long responsibility chain, the processing of requests may involve multiple processing objects, and the system performance will be affected to some extent;
The rationality of the establishment of responsibility chain depends on the client, which increases the complexity of the client, and may lead to system errors due to the wrong setting of responsibility chain, such as circular call.
Structure of mode:
The responsibility chain model mainly includes the following roles.
Abstract Handler role: define an interface for processing requests, including abstract processing methods and a subsequent connection;
Concrete Handler role: implement the processing method of the abstract handler to judge whether the request can be processed. If the request can be processed, process it. Otherwise, transfer the request to its successor;
Client role: create a processing chain and submit a request to the specific handler object of the chain head. It does not care about the processing details and the transmission process of the request.
The essence of responsibility chain mode is to decouple request and processing, so that requests can be transmitted and processed in the processing chain; Understanding the responsibility chain model should understand its model, not its specific implementation. The unique feature of the responsibility chain model is that it combines the node processors into a chain structure, and allows the node to decide whether to process or forward the request, which is equivalent to making the request flow
Implementation of mode:
package chainOfResponsibility; public class ChainOfResponsibilityPattern { public static void main(String[] args) { //Assembly responsibility chain Handler handler1 = new ConcreteHandler1(); Handler handler2 = new ConcreteHandler2(); handler1.setNext(handler2); //Submit request handler1.handleRequest("two"); } } //Abstract handler role abstract class Handler { private Handler next; public void setNext(Handler next) { this.next = next; } public Handler getNext() { return next; } //Method of processing request public abstract void handleRequest(String request); } //Specific processor role 1 class ConcreteHandler1 extends Handler { public void handleRequest(String request) { if (request.equals("one")) { System.out.println("Specific handler 1 is responsible for processing the request!"); } else { if (getNext() != null) { getNext().handleRequest(request); } else { System.out.println("No one is processing the request!"); } } } } //Specific processor role 2 class ConcreteHandler2 extends Handler { public void handleRequest(String request) { if (request.equals("two")) { System.out.println("Specific handler 2 is responsible for processing the request!"); } else { if (getNext() != null) { getNext().handleRequest(request); } else { System.out.println("No one is processing the request!"); } } } }
17. State mode
For stateful objects, the complex "judgment logic" is extracted into different state objects, allowing the state object to change its behavior when its internal state changes.
Advantages and disadvantages of the mode:
Its main advantages are as follows:
The structure is clear, and the state mode localizes the behaviors related to a specific state into one state, and separates the behaviors in different states to meet the "single responsibility principle";
Display the state transition to reduce the interdependence between objects. Introducing different states into independent objects will make the state transition more explicit and reduce the interdependence between objects;
The responsibilities of the status class are clear, which is conducive to the expansion of the program. It is easy to add new states and transitions by defining new subclasses.
The main disadvantages are as follows:
The use of state mode will inevitably increase the number of classes and objects of the system;
The structure and implementation of state mode are complex, and improper use will lead to confusion of program structure and code;
The state mode does not support the opening and closing principle very well. For the state mode that can switch states, adding a new state class requires modifying the source code responsible for state transformation, otherwise it cannot switch to the new state, and modifying the behavior of a state class also requires modifying the source code of the corresponding class.
Structure of mode:
State mode packages the behavior of objects changed by the environment in different state objects. Its intention is to make an object change its behavior when its internal state changes.
The status mode contains the following main roles:
Context role: also known as context, it defines the interface required by the client, internally maintains a current state, and is responsible for switching specific states;
Abstract State role: define an interface to encapsulate the behavior corresponding to a specific State in the environment object. There can be one or more behaviors;
Concrete State role: implement the behavior corresponding to the abstract state, and switch the state if necessary.
Implementation of mode:
public class StatePatternClient { public static void main(String[] args) { Context context = new Context(); //Create environment context.Handle(); //Processing requests context.Handle(); context.Handle(); context.Handle(); } } //Environment class class Context { private State state; //Defines the initial state of the environment class public Context() { this.state = new ConcreteStateA(); } //Set new status public void setState(State state) { this.state = state; } //Read status public State getState() { return (state); } //Processing requests public void Handle() { state.Handle(this); } } //Abstract state class abstract class State { public abstract void Handle(Context context); } //Specific status class A class ConcreteStateA extends State { public void Handle(Context context) { System.out.println("Current status is A."); context.setState(new ConcreteStateB()); } } //Specific status class B class ConcreteStateB extends State { public void Handle(Context context) { System.out.println("Current status is B."); context.setState(new ConcreteStateA()); } }
18. Observer mode (observer)
Define a one to many dependency between objects so that when the state of an object changes, all objects that depend on it are notified and refreshed automatically.
Advantages and disadvantages of the mode:
The advantages are as follows:
It reduces the coupling relationship between the target and the observer, which is an abstract coupling relationship. Comply with the principle of Dependence Inversion;
A trigger mechanism is established between the target and the observer.
The disadvantages are as follows:
The dependency between the target and the observer is not completely removed, and circular references may occur;
When there are many observers, the announcement takes a lot of time, which affects the efficiency of the program.
Structure of mode:
When implementing observer mode, it should be noted that the specific target object and the specific observer object cannot be called directly, otherwise they will be closely coupled, which violates the object-oriented design principle.
The main roles of the observer model are as follows:
Abstract Subject role: also known as abstract target class, it provides an aggregation class for saving observer objects, methods for adding and deleting observer objects, and abstract methods for notifying all observers;
Concrete Subject role: also known as concrete target class, it implements the notification method in the abstract target. When the internal state of a specific subject changes, it notifies all registered observer objects;
Abstract Observer role: it is an abstract class or interface, which contains an abstract method to update itself. It is called when receiving the change notification of a specific topic;
Concrete Observer role: implement the abstract method defined in the abstract observer to update its status when notified of the change of the target.
Implementation of mode:
package net.biancheng.c.observer; import java.util.*; public class ObserverPattern { public static void main(String[] args) { Subject subject = new ConcreteSubject(); Observer obs1 = new ConcreteObserver1(); Observer obs2 = new ConcreteObserver2(); subject.add(obs1); subject.add(obs2); subject.notifyObserver(); } } //Abstract goal abstract class Subject { protected List<Observer> observers = new ArrayList<Observer>(); //Add observer method public void add(Observer observer) { observers.add(observer); } //Delete observer method public void remove(Observer observer) { observers.remove(observer); } public abstract void notifyObserver(); //Method of notifying the observer } //Specific objectives class ConcreteSubject extends Subject { public void notifyObserver() { System.out.println("The specific objectives have changed..."); System.out.println("--------------"); for (Object obs : observers) { ((Observer) obs).response(); } } } //Abstract observer interface Observer { void response(); //reaction } //Specific observer 1 class ConcreteObserver1 implements Observer { public void response() { System.out.println("Specific observer 1 responds!"); } } //Specific observer 1 class ConcreteObserver2 implements Observer { public void response() { System.out.println("Specific observer 2 responds!"); } }
19. Mediator mode
Define a mediation object to encapsulate the interaction between a series of objects, so that the coupling between the original objects is loose, and the interaction between them can be changed independently. Mediators make objects do not need to explicitly refer to each other, so that they are loosely coupled, and their interaction can be changed independently.
Advantages and disadvantages of the mode:
The advantages are as follows:
Each class performs its own duties, which conforms to Dimitri's law;
The coupling between objects is reduced, so that objects can be reused independently;
The one-to-many association between objects is transformed into one-to-one association, which improves the flexibility of the system and makes the system easy to maintain and expand.
The disadvantages are:
The mediator pattern turns the direct interdependence of multiple objects into the dependency between the mediator and multiple colleague classes. When there are more colleagues, intermediaries will become more bloated, complex and difficult to maintain.
Structure of mode:
The mediator pattern contains the following main roles:
Abstract Mediator role: it is the interface of Mediator and provides abstract methods for registering and forwarding colleague object information;
Concrete Mediator role: implement the mediator interface, define a List to manage colleague objects and coordinate the interaction between various colleague roles. Therefore, it depends on colleague roles;
Abstract Colleague class role: define the interface of Colleague class, save the mediator object, provide abstract methods for Colleague object interaction, and realize the public functions of all interacting Colleague classes;
Concrete Colleague role: it is the implementer of the abstract colleague class. When it is necessary to interact with other colleague objects, the mediator object is responsible for the subsequent interaction.
Implementation of mode:
package net.biancheng.c.mediator; import java.util.*; public class MediatorPattern { public static void main(String[] args) { Mediator md = new ConcreteMediator(); Colleague c1, c2; c1 = new ConcreteColleague1(); c2 = new ConcreteColleague2(); md.register(c1); md.register(c2); c1.send(); System.out.println("-------------"); c2.send(); } } //Abstract mediator abstract class Mediator { public abstract void register(Colleague colleague); public abstract void relay(Colleague cl); //forward } //Specific intermediary class ConcreteMediator extends Mediator { private List<Colleague> colleagues = new ArrayList<Colleague>(); public void register(Colleague colleague) { if (!colleagues.contains(colleague)) { colleagues.add(colleague); colleague.setMedium(this); } } public void relay(Colleague cl) { for (Colleague ob : colleagues) { if (!ob.equals(cl)) { ((Colleague) ob).receive(); } } } } //Abstract colleague class abstract class Colleague { protected Mediator mediator; public void setMedium(Mediator mediator) { this.mediator = mediator; } public abstract void receive(); public abstract void send(); } //Specific colleagues class ConcreteColleague1 extends Colleague { public void receive() { System.out.println("Specific colleague class 1 received the request."); } public void send() { System.out.println("Specific colleague class 1 sends a request."); mediator.relay(this); //Ask the intermediary to forward } } //Specific colleagues class ConcreteColleague2 extends Colleague { public void receive() { System.out.println("Specific colleague class 2 received the request."); } public void send() { System.out.println("Specific colleague class 2 sends a request."); mediator.relay(this); //Ask the intermediary to forward } }
20. Iterator mode (iterator)
Provides a method to sequentially access the elements of an aggregate object without exposing the internal representation of the object.
Advantages and disadvantages of the mode:
The advantages are as follows:
Accessing the contents of an aggregate object without exposing its internal representation;
The traversal task is completed by the iterator, which simplifies the aggregation class;
It supports traversal of an aggregate in different ways, and can even customize the subclass of the iterator to support new traversal;
It is convenient to add new aggregation classes and iterator classes without modifying the original code;
It has good encapsulation and provides a unified interface for traversing different aggregation structures.
Its main disadvantage is that it increases the number of classes, which increases the complexity of the system to a certain extent.
Structure of mode:
The iterator pattern is realized by separating the traversal behavior of the aggregated object and abstracting it into an iterator class. Its purpose is to make the external code access the aggregated internal data transparently without exposing the internal structure of the aggregated object.
The iterator pattern mainly includes the following roles:
Abstract Aggregate role: define interfaces for storing, adding, deleting Aggregate objects and creating iterator objects;
Concrete aggregate role: implement the abstract aggregate class and return an instance of a concrete iterator;
Abstract Iterator role: define interfaces for accessing and traversing aggregation elements, usually including hasNext(), first(), next(), etc;
Concrete iterator role: implement the methods defined in the abstract iterator interface, complete the traversal of aggregate objects, and record the current location of traversal.
Implementation of mode:
package net.biancheng.c.iterator; import java.util.*; public class IteratorPattern { public static void main(String[] args) { Aggregate ag = new ConcreteAggregate(); ag.add("Sun Yat-sen University"); ag.add("South China Institute of Technology"); ag.add("shaoguan university "); System.out.print("The aggregated contents include:"); Iterator it = ag.getIterator(); while (it.hasNext()) { Object ob = it.next(); System.out.print(ob.toString() + "\t"); } Object ob = it.first(); System.out.println("\nFirst: " + ob.toString()); } } //Abstract aggregation interface Aggregate { public void add(Object obj); public void remove(Object obj); public Iterator getIterator(); } //Specific aggregation class ConcreteAggregate implements Aggregate { private List<Object> list = new ArrayList<Object>(); public void add(Object obj) { list.add(obj); } public void remove(Object obj) { list.remove(obj); } public Iterator getIterator() { return (new ConcreteIterator(list)); } } //Abstract iterator interface Iterator { Object first(); Object next(); boolean hasNext(); } //Concrete iterator class ConcreteIterator implements Iterator { private List<Object> list = null; private int index = -1; public ConcreteIterator(List<Object> list) { this.list = list; } public boolean hasNext() { if (index < list.size() - 1) { return true; } else { return false; } } public Object first() { index = 0; Object obj = list.get(index); ; return obj; } public Object next() { Object obj = null; if (this.hasNext()) { obj = list.get(++index); } return obj; } }
21. Visitor mode
The operations acting on each element in a data structure are separated and encapsulated into independent classes, so that it can add new operations acting on these elements without changing the data structure, and provide a variety of access methods for each element in the data structure.
Advantages and disadvantages of the mode:
The advantages are as follows:
Good scalability. It can add new functions to the elements in the object structure without modifying the elements in the object structure;
Good reusability. Visitors can define the general functions of the whole object structure, so as to improve the reuse degree of the system;
Good flexibility. Visitor mode decouples the data structure from the operations acting on the structure, so that the operation set can evolve relatively freely without affecting the data structure of the system;
Comply with the principle of single responsibility. Visitor mode encapsulates the relevant behaviors to form a visitor, so that the function of each visitor is relatively single.
The main disadvantages are as follows:
Adding new element classes is difficult. In the visitor mode, every time a new element class is added, corresponding specific operations must be added to each specific visitor class, which violates the "opening and closing principle";
Destroy the package. In the visitor pattern, specific elements publish details to visitors, which destroys the encapsulation of objects;
Violation of the dependency inversion principle. The visitor pattern relies on concrete classes instead of abstract classes.
Structure of mode:
The visitor pattern contains the following main roles:
Abstract Visitor role: define an interface to access specific elements. Each specific element class corresponds to an access operation visit(). The parameter type in the operation identifies the accessed specific elements;
Concrete visitor role: implement each access operation declared in the abstract visitor role and determine what visitors should do when accessing an element;
Abstract Element role: declare an interface containing the accept operation accept(), and the accepted visitor object is used as the parameter of the accept() method;
Concrete element role: implement the accept() operation provided by the abstract element role. Its method body is usually visitor.visit(this). In addition, the specific element may also contain relevant operations of its own business logic;
Object Structure role: it is a container containing element roles and provides methods for visitor objects to traverse all elements in the container. It is usually implemented by aggregate classes such as List, Set and Map.
Implementation of mode:
package net.biancheng.c.visitor; import java.util.*; public class VisitorPattern { public static void main(String[] args) { ObjectStructure os = new ObjectStructure(); os.add(new ConcreteElementA()); os.add(new ConcreteElementB()); Visitor visitor = new ConcreteVisitorA(); os.accept(visitor); System.out.println("------------------------"); visitor = new ConcreteVisitorB(); os.accept(visitor); } } //Abstract Visitor interface Visitor { void visit(ConcreteElementA element); void visit(ConcreteElementB element); } //Specific visitor class A class ConcreteVisitorA implements Visitor { public void visit(ConcreteElementA element) { System.out.println("Specific visitors A visit-->" + element.operationA()); } public void visit(ConcreteElementB element) { System.out.println("Specific visitors A visit-->" + element.operationB()); } } //Specific visitor class B class ConcreteVisitorB implements Visitor { public void visit(ConcreteElementA element) { System.out.println("Specific visitors B visit-->" + element.operationA()); } public void visit(ConcreteElementB element) { System.out.println("Specific visitors B visit-->" + element.operationB()); } } //Abstract element class interface Element { void accept(Visitor visitor); } //Specific element class A class ConcreteElementA implements Element { public void accept(Visitor visitor) { visitor.visit(this); } public String operationA() { return "Specific elements A Operation of."; } } //Specific element class B class ConcreteElementB implements Element { public void accept(Visitor visitor) { visitor.visit(this); } public String operationB() { return "Specific elements B Operation of."; } } //Object structure role class ObjectStructure { private List<Element> list = new ArrayList<Element>(); public void accept(Visitor visitor) { Iterator<Element> i = list.iterator(); while (i.hasNext()) { ((Element) i.next()).accept(visitor); } } public void add(Element element) { list.add(element); } public void remove(Element element) { list.remove(element); } }
22. Memo mode
Without breaking the encapsulation, capture the internal state of an object and save the state outside the object. This will restore the object to the saved state later.
Advantages and disadvantages of the mode:
The main advantages are as follows:
Provides a mechanism to restore state. When users need it, they can easily restore the data to a historical state;
The encapsulation of internal state is realized. Except for the initiator who created it, no other object can access these status information;
Simplified the human. The initiator does not need to manage and save each backup of its internal status. All status information is saved in the memo and managed by the manager, which is in line with the principle of single responsibility.
Its main disadvantage is: high resource consumption. If the internal state information to be saved is too much or too frequent, it will occupy a large memory resource.
Structure of mode:
The main roles of the memo model are as follows:
Initiator role: record the internal status information at the current time, provide the function of creating memos and recovering memo data, and realize other business functions. It can access all the information in memos;
Memo role: responsible for storing the internal status of the initiator and providing these internal status to the initiator when necessary;
Caretaker role: manages memos and provides the function of saving and obtaining memos, but it cannot access and modify the contents of memos.
Implementation of mode:
package net.biancheng.c.memento; public class MementoPattern { public static void main(String[] args) { Originator or = new Originator(); Caretaker cr = new Caretaker(); or.setState("S0"); System.out.println("Initial state:" + or.getState()); cr.setMemento(or.createMemento()); //Save status or.setState("S1"); System.out.println("New status:" + or.getState()); or.restoreMemento(cr.getMemento()); //Restore state System.out.println("Restore state:" + or.getState()); } } //memorandum class Memento { private String state; public Memento(String state) { this.state = state; } public void setState(String state) { this.state = state; } public String getState() { return state; } } //Initiator class Originator { private String state; public void setState(String state) { this.state = state; } public String getState() { return state; } public Memento createMemento() { return new Memento(state); } public void restoreMemento(Memento m) { this.setState(m.getState()); } } //controller class Caretaker { private Memento memento; public void setMemento(Memento m) { memento = m; } public Memento getMemento() { return memento; } }
23. Interpreter mode
Given a language, define a representation of its grammar and define an interpreter that uses the representation to interpret sentences in the language. In other words, use the compiled language to analyze the examples in the application.
Advantages and disadvantages of the mode:
The main advantages are as follows:
Good scalability. Since classes are used to represent the grammar rules of the language in the interpreter mode, the grammar can be changed or extended through mechanisms such as inheritance;
Easy to implement. Each expression node class in the syntax tree is similar, so it is easier to implement its grammar.
The disadvantages are as follows:
Low execution efficiency. The interpreter mode usually uses a large number of loops and recursive calls. When the sentences to be interpreted are complex, the running speed is very slow, and the debugging process of the code is also troublesome;
Will cause class expansion. Each rule in the interpreter mode needs to define at least one class. When there are many grammar rules, the number of classes will increase sharply, making it difficult for the system to manage and maintain;
There are few applicable scenarios. In software development, there are very few application examples that need to define language grammar, so this model is rarely used.
Structure of mode:
The Interpreter pattern contains the following main roles:
Abstract Expression role: define the interface of the interpreter and agree the interpretation operation of the interpreter, mainly including the interpretation method interpret();
Terminal Expression role: it is a subclass of abstract expression, which is used to implement operations related to terminals in grammar. Each terminal in grammar has a specific Terminal Expression corresponding to it;
Non terminal expression role: it is also a subclass of abstract expression, which is used to realize the operations related to non terminal in grammar. Each rule in grammar corresponds to a non terminal expression;
Context role: it usually contains the data or common functions required by each interpreter. It is generally used to transfer the data shared by all interpreters. Subsequent interpreters can obtain these values from here;
Client (Client): the main task is to translate the sentences or expressions that need analysis into the abstract syntax tree described by the interpreter object, then invoke the interpreter's interpretation method, and of course, can indirectly access the interpreter's interpretation method through the role of the environment.
Implementation of mode:
The key to the implementation of interpreter mode is to define grammar rules, design terminator classes and non terminator classes, draw structure diagrams, and build syntax trees if necessary. The code structure is as follows:
package net.biancheng.c.interpreter; //Abstract expression class interface AbstractExpression { public void interpret(String info); //Interpretation method } //Terminator expression class class TerminalExpression implements AbstractExpression { public void interpret(String info) { //Processing of terminator expressions } } //Non terminator expression class class NonterminalExpression implements AbstractExpression { private AbstractExpression exp1; private AbstractExpression exp2; public void interpret(String info) { //Processing of non terminator expressions } } //Environment class class Context { private AbstractExpression exp; public Context() { //Data initialization } public void operation(String info) { //Call the interpretation method of the related expression class } }
You are very good at seeing here. Please give me a compliment. Thank you~