JAVA Design Patterns Study Notes: Creation Patterns - 01

Six principles of design patterns

  • 1. Open Close Principle
    • The open-closed principle means: open for extension, closed for modification. When the program needs to be expanded, the original code cannot be modified to achieve a hot-plug effect. In short, it is to make the program expandable, easy to maintain and upgrade. To achieve this effect, we need to use interfaces and abstract classes.
  • 2. Liskov Substitution Principle
    • The Liskov Substitution Principle is one of the basic principles of object-oriented design. The Liskov Substitution Principle states that wherever a base class can appear, a subclass must appear. LSP is the cornerstone of inheritance and reuse. Only when the derived class can replace the base class and the function of the software unit is not affected, the base class can be truly reused, and the derived class can also add new ones on the basis of the base class. behavior. The Liskov Substitution Principle is a complement to the Open-Closed Principle. The key step to realize the open-closed principle is abstraction, and the inheritance relationship between the base class and the subclass is the concrete realization of abstraction, so the Liskov substitution principle is the specification of the concrete steps to realize abstraction.
  • 3. Dependence Inversion Principle
    • This principle is the basis of the open-closed principle, concrete content: programming against interfaces, relying on abstraction rather than concreteness.
  • 4. Interface Segregation Principle
    • What this principle means is that it is better to use multiple isolated interfaces than to use a single interface. It has another meaning: reduce the coupling between classes. It can be seen that, in fact, the design pattern is a software design idea that starts from a large-scale software architecture and is easy to upgrade and maintain. It emphasizes reducing dependencies and coupling.
  • 5. The Law of Demeter, also known as the least known principle (Demeter Principle)
    • The principle of least-knowing means that an entity should interact with other entities as little as possible, so that the functional modules of the system are relatively independent.
  • 6. Composite Reuse Principle
    • The principle of composition reuse means: try to use composition/aggregation instead of inheritance.

creative mode

  • These design patterns provide a way to hide the creation logic while creating an object, instead of using the new operator to instantiate the object directly. This makes the program more flexible in deciding which objects need to be created for a given instance.

Factory Pattern

  • Intent: Define an interface for creating an object, let its subclasses decide which factory class to instantiate, and the factory pattern delays the creation process to subclasses.

  • When to use: When we explicitly plan to create different instances under different conditions.

  • How to solve: Let its subclass implement the factory interface, and the returned product is also an abstract product.

  • Advantages: 1. If a caller wants to create an object, it only needs to know its name. 2. High scalability. If you want to add a product, you only need to extend a factory class. 3. The specific implementation of the shielding product is shielded, and the caller only cares about the interface of the product.

  • Disadvantage: Every time a product is added, a specific class and object implementation factory need to be added, which doubles the number of classes in the system, increases the complexity of the system to a certain extent, and also increases the specific class of the system. rely. This is not a good thing.

  • Usage scenarios: 1. Logger: Records may be recorded to the local hard disk, system events, remote servers, etc. The user can choose where to record the log. 2. Database access, when the user does not know which type of database the system uses in the end, and when the database may change. 3. To design a framework for connecting to a server, three protocols are needed, "POP3", "IMAP", and "HTTP". These three can be used as product classes to jointly implement an interface.

  • Note: As a class creation pattern, you can use the factory method pattern anywhere you need to generate complex objects. One thing to note is that complex objects are suitable for using the factory pattern, while simple objects, especially those that can be created only through new, do not need to use the factory pattern. If you use the factory pattern, you need to introduce a factory class, which will increase the complexity of the system.
    write picture description here

    write picture description here

https://gof.quanke.name/%E5%B7%A5%E5%8E%82%E4%B8%89%E5%85%84%E5%BC%9F%E4%B9%8B%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F%EF%BC%88%E5%9B%9B%EF%BC%89.html

Abstract Factory Pattern

  • Intent: To provide an interface for creating a series of related or interdependent objects without specifying their concrete classes.

  • Main solution: mainly solve the problem of interface selection.

  • When to use: The product of the system has more than one product family, and the system only consumes the product of one family.

  • Application example: At work, in order to attend some parties, there must be two or more sets of clothes, such as business clothes (complete sets, a series of specific products), fashion clothes (complete sets, a series of specific products), even for a family For example, there may be business women's clothing, business men's clothing, fashion women's clothing, fashion men's clothing, and these are also complete sets, that is, a series of specific products. Suppose a situation (it does not exist in reality, otherwise, it is impossible to enter communism, but it is helpful to illustrate the abstract factory model), in your home, a certain wardrobe (specific factory) can only store a certain kind of such clothes (sets, a series of specific products), which naturally have to be taken out of this wardrobe every time you take this set of clothes. To understand with the idea of ​​OO, all wardrobes (concrete factories) are one of the wardrobes (abstract factories), and each complete set of clothes includes a specific top (a specific product), pants (a specific product). Products), these concrete tops are actually tops (abstract products), and concrete pants are also pants (another abstract product).

  • Advantage: When multiple objects in a product family are designed to work together, it ensures that clients always use only objects from the same product family.

  • Disadvantage: It is very difficult to expand the product family. To add a certain product of a series, it is necessary to add code in the abstract Creator and add code in the concrete.

  • Usage scenarios: 1. QQ changes skins, and a whole set is changed together. 2. Generate programs for different operating systems.
    write picture description here

  • Sunny software company wants to develop a set of interface skin library design
    write picture description here
  • Sunny software company wants to develop a set of interface skin library architecture
    write picture description here
  • Abstract Factory Pattern: Provides an interface for creating a series of related or interdependent objects without specifying their specific classes. The abstract factory pattern, also known as the Kit pattern, is an object creation pattern.
  • In the abstract factory pattern, each concrete factory provides multiple factory methods for producing a variety of different types of products, these products constitute a product family, the structure of the abstract factory pattern is shown in the figure:
    write picture description here
  • The abstract factory pattern structure diagram includes the following roles:
    • AbstractFactory (Abstract Factory): It declares a set of methods used to create a family of products, each method corresponds to a product.
    • ConcreteFactory (concrete factory): It implements the method of creating products declared in the abstract factory, and generates a set of concrete products, which constitute a product family, each product is located in a certain product hierarchy.
    • AbstractProduct (abstract product): It declares the interface for each product, and declares the business methods that the product has in the abstract product.
    • ConcreteProduct: It defines a concrete product object produced by a concrete factory, implementing the business methods declared in the abstract product interface.
  • The developers of Sunny Company use the abstract factory pattern to reconstruct the design of the interface skin library. The basic structure is shown in the figure:
    write picture description here
//在本实例中我们对代码进行了大量简化,实际使用时,界面组件的初始化代码较为复杂,还需要使用JDK中一些已有类,为了突出核心代码,在此只提供框架代码和演示输出。  
//按钮接口:抽象产品  
interface Button {  
    public void display();  
}  

//Spring按钮类:具体产品  
class SpringButton implements Button {  
    public void display() {  
        System.out.println("显示浅绿色按钮。");  
    }  
}  

//Summer按钮类:具体产品  
class SummerButton implements Button {  
    public void display() {  
        System.out.println("显示浅蓝色按钮。");  
    }     
}  

//文本框接口:抽象产品  
interface TextField {  
    public void display();  
}  

//Spring文本框类:具体产品  
class SpringTextField implements TextField {  
    public void display() {  
        System.out.println("显示绿色边框文本框。");  
    }  
}  

//Summer文本框类:具体产品  
class SummerTextField implements TextField {  
    public void display() {  
        System.out.println("显示蓝色边框文本框。");  
    }     
}  

//组合框接口:抽象产品  
interface ComboBox {  
    public void display();  
}  

//Spring组合框类:具体产品  
class SpringComboBox implements ComboBox {  
    public void display() {  
        System.out.println("显示绿色边框组合框。");  
    }  
}  

//Summer组合框类:具体产品  
class SummerComboBox implements ComboBox {  
    public void display() {  
        System.out.println("显示蓝色边框组合框。");  
    }     
}  

//界面皮肤工厂接口:抽象工厂  
interface SkinFactory {  
    public Button createButton();  
    public TextField createTextField();  
    public ComboBox createComboBox();  
}  

//Spring皮肤工厂:具体工厂  
class SpringSkinFactory implements SkinFactory {  
    public Button createButton() {  
        return new SpringButton();  
    }  

    public TextField createTextField() {  
        return new SpringTextField();  
    }  

    public ComboBox createComboBox() {  
        return new SpringComboBox();  
    }  
}  

//Summer皮肤工厂:具体工厂  
class SummerSkinFactory implements SkinFactory {  
    public Button createButton() {  
        return new SummerButton();  
    }  

    public TextField createTextField() {  
        return new SummerTextField();  
    }  

    public ComboBox createComboBox() {  
        return new SummerComboBox();  
    }  
}

singleton design pattern

  • Intent: To ensure that there is only one instance of a class, and to provide a global access point to it.

  • The main solution: a globally used class is frequently created and destroyed.

  • When to use: When you want to control the number of instances and save system resources.

  • How to solve: Determine whether the system already has this singleton, if so, return it, if not, create it.

  • Key code: The constructor is private.

  • Application examples: 1. A party can only have one chairman. 2. Windows is multi-process and multi-threaded. When operating a file, it is inevitable that multiple processes or threads operate a file at the same time, so the processing of all files must be carried out through a unique instance. 3. Some device managers are often designed as a singleton mode. For example, a computer has two printers. When outputting, it is necessary to process that the two printers cannot print the same file.

  • Advantages: 1. There is only one instance in the memory, which reduces the memory overhead, especially the frequent creation and destruction of instances (such as the home page cache of the School of Management). 2. Avoid multiple occupation of resources (such as file writing operations).

  • Disadvantages: No interface, no inheritance, conflicts with the principle of single responsibility, a class should only care about the internal logic, not how to instantiate it outside.

  • Usage scenarios: 1. It is required to produce a unique serial number. 2. The counter in the WEB does not need to be added to the database every time it is refreshed, but is cached first with a singleton. 3. An object created needs to consume too many resources, such as the connection between I/O and the database.

  • Note: The getInstance() method needs to use a synchronization lock synchronized (Singleton.class) to prevent multiple threads from entering at the same time and causing instance to be instantiated multiple times.
    write picture description here

  • Through analysis and trade-offs, the developers of Sunny Company decided to use the singleton pattern to design the load balancer. The structure diagram is shown in the figure:
    write picture description here
  • Lazy-style perfect for thread safety
    • If both thread A and thread B are calling the getInstance() method at a certain moment, and the instance object is null at this time, the judgment of instance == null can be passed. Due to the implementation of the synchronized locking mechanism, thread A enters the synchronized locked code to execute the instance creation code, while thread B is in a queued waiting state and must wait for thread A to finish executing before entering the synchronized locked code. However, when A finishes executing, thread B does not know that the instance has been created, and will continue to create new instances, resulting in the generation of multiple singleton objects, which violates the design idea of ​​the singleton pattern, so it needs to be further improved, and then in synchronized Once (instance == null) judgment, this method is called double-check locking (Double-Check Locking). The complete code for a lazy singleton class implemented using double-checked locking looks like this:
class LazySingleton {   
    private volatile static LazySingleton instance = null;   

    private LazySingleton() { }   

    public static LazySingleton getInstance() {   
        //第一重判断  
        if (instance == null) {  
            //锁定代码块  
            synchronized (LazySingleton.class) {  
                //第二重判断  
                if (instance == null) {  
                    instance = new LazySingleton(); //创建单例实例  
                }  
            }  
        }  
        return instance;   
    }  
}
  • Hungry-style singleton classes cannot implement lazy loading, and will always occupy memory regardless of future use; lazy-style singleton classes are cumbersome to control thread safety, and their performance is affected. It can be seen that there are such problems as hungry singletons and lazy singletons. Is there a way to overcome the shortcomings of both singletons and combine the advantages of both? The answer is: Yes! Let's learn this better technique called Initialization Demand Holder (IoDH).
  • In IoDH, we add a static inner class to the singleton class, create a singleton object in the inner class, and then return the singleton object to external use through the getInstance() method. The implementation code is as follows :
//Initialization on Demand Holder  
class Singleton {  
    private Singleton() {  
    }  

    private static class HolderClass {  
            private final static Singleton instance = new Singleton();  
    }  

    public static Singleton getInstance() {  
        return HolderClass.instance;  
    }  

    public static void main(String args[]) {  
        Singleton s1, s2;   
            s1 = Singleton.getInstance();  
        s2 = Singleton.getInstance();  
        System.out.println(s1==s2);  
    }  
}

prototype mode

  • The Prototype Pattern is used to create repetitive objects while maintaining performance. This type of design pattern is a creational pattern, which provides an optimal way to create objects.
  • Intent: Use prototype instances to specify the kind of objects to create, and create new objects by copying these prototypes.

  • Main solution: build and delete prototypes at runtime.

  • When to use: 1. When a system should be created, composed and represented independently of its product. 2. When the class to be instantiated is specified at runtime, for example, by dynamic loading. 3. To avoid creating a factory class hierarchy parallel to the product class hierarchy. 4. When an instance of a class can only have one of several different state combinations. It may be more convenient to build a corresponding number of prototypes and clone them than to manually instantiate the class with the appropriate state each time.

  • How to solve: Use an existing prototype object to quickly generate the same instance as the prototype object.

  • Key code: 1. To implement clone operation, inherit Cloneable in JAVA, rewrite clone(), in .NET, you can use MemberwiseClone() method of Object class to realize shallow copy of object or realize deep copy through serialization. 2. The prototype pattern is also used to isolate the coupling relationship between the user of the class object and the specific type (mutable class), and it also requires these "mutable classes" to have stable interfaces.

  • Application examples: 1. Cell division. 2. Object clone() method in JAVA.

  • Advantages: 1. Improved performance. 2. Escape the constraints of the constructor.

  • Disadvantages: 1. Equipping the clone method requires comprehensive consideration of the functions of the class, which is not difficult for a brand-new class, but not necessarily easy for an existing class, especially when a class refers to an indirect object that does not support serialization, Or when the reference contains a cyclic structure. 2. The Cloneable interface must be implemented.

  • Usage scenarios: 1. Resource optimization scenarios. 2. Class initialization needs to digest a lot of resources, including data and hardware resources. 3. Scenarios with performance and security requirements. 4. To generate an object through new requires very tedious data preparation or access rights, you can use the prototype mode. 5. A scene with multiple modifiers for one object. 6. When an object needs to be provided to other objects for access, and each caller may need to modify its value, consider using the prototype mode to copy multiple objects for the caller to use. 7. In actual projects, the prototype pattern rarely appears alone, and generally appears together with the factory method pattern. An object is created by the clone method, and then provided to the caller by the factory method. The prototype pattern has been integrated into Java, and you can use it wherever you go.

  • Note: Instead of constructing a new object by instantiating a class, the prototype pattern creates a new object by copying an existing object. Shallow copy implements Cloneable, rewrite, deep copy is to read binary stream by implementing Serializable.

  • Shallow clone:
    • In shallow cloning, if the member variable of the prototype object is a value type, a copy will be made to the cloned object; if the member variable of the prototype object is a reference type, a copy of the address of the reference object will be copied to the cloned object, that is, the prototype The member variables of the object and the cloned object point to the same memory address. In simple terms, in shallow clone, when the object is copied, only itself and the member variables of the value type contained in it are copied, and the member objects of the reference type are not copied
      write picture description here
      write picture description here
  • 2. Deep Cloning
    • In deep cloning, no matter whether the member variable of the prototype object is a value type or a reference type, a copy will be made to the cloned object, and a copy of all the reference objects of the prototype object will also be copied to the cloned object. In simple terms, in a deep clone, in addition to the object itself being copied, all member variables contained in the object are also copied
      write picture description here
      write picture description here
//使用序列化技术实现深克隆
       public WeeklyLog deepClone() throws  IOException, ClassNotFoundException, OptionalDataException
       {
              //将对象写入流中
              ByteArrayOutputStream bao=new  ByteArrayOutputStream();
              ObjectOutputStream oos=new  ObjectOutputStream(bao);
              oos.writeObject(this);

              //将对象从流中取出
              ByteArrayInputStream bis=new  ByteArrayInputStream(bao.toByteArray());
              ObjectInputStream ois=new  ObjectInputStream(bis);
              return  (WeeklyLog)ois.readObject();
       }

write picture description here

  • Design of Document Manager Using Prototype Mode with Prototype Manager
    write picture description here
import java.util.*;

//抽象公文接口,也可定义为抽象类,提供clone()方法的实现,将业务方法声明为抽象方法
interface OfficialDocument extends Cloneable {
    public OfficialDocument clone();

    public void display();
}

//可行性分析报告(Feasibility Analysis Report)类
class FAR implements OfficialDocument {
    public OfficialDocument clone() {
        OfficialDocument far = null;
        try {
            far = (OfficialDocument) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("不支持复制!");
        }
        return far;
    }

    public void display() {
        System.out.println("《可行性分析报告》");
    }
}

//软件需求规格说明书(Software Requirements Specification)类
class SRS implements OfficialDocument {
    public OfficialDocument clone() {
        OfficialDocument srs = null;
        try {
            srs = (OfficialDocument) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("不支持复制!");
        }
        return srs;
    }

    public void display() {
        System.out.println("《软件需求规格说明书》");
    }
}

//原型管理器(使用饿汉式单例实现)
class PrototypeManager {
    //定义一个Hashtable,用于存储原型对象
    private Hashtable ht = new Hashtable();
    private static PrototypeManager pm = new PrototypeManager();

    //为Hashtable增加公文对象   
    private PrototypeManager() {
        ht.put("far", new FAR());
        ht.put("srs", new SRS());
    }

    //增加新的公文对象
    public void addOfficialDocument(String key, OfficialDocument doc) {
        ht.put(key, doc);
    }

    //通过浅克隆获取新的公文对象
    public OfficialDocument getOfficialDocument(String key) {
        return ((OfficialDocument) ht.get(key)).clone();
    }

    public static PrototypeManager getPrototypeManager() {
        return pm;
    }
}

creator mode

  • The builder pattern, also known as the generator pattern, is a relatively complex and relatively infrequently used creation pattern. The builder pattern returns not a simple product to the client, but a complex product consisting of multiple parts.
  • Intent: To separate a complex build from its representation so that the same build process can create different representations.

  • Main solution: The main solution is to solve the problem of creating a "complex object" in a software system, which is usually composed of sub-objects of various parts with a certain algorithm; due to changes in requirements, various parts of this complex object often face drastic changes, but the algorithms that combine them are relatively stable.

  • When to use: When some basic components do not change, but their combinations change frequently.

  • How to fix it: Separate change from change.

  • Key code: Builder: Create and provide instances, Director: Manage dependencies of built instances.

  • Application examples: 1. When going to KFC, hamburgers, cola, french fries, fried chicken wings, etc. are unchanged, and their combinations are often changed, resulting in a so-called "package". 2. StringBuilder in JAVA.

  • Advantages: 1. The builder is independent and easy to expand. 2. It is easy to control the risk of details.

  • Disadvantages: 1. The products must have something in common, and the scope is limited. 2. If the internal changes are complicated, there will be many construction types.

  • Usage scenarios: 1. The objects to be generated have complex internal structures. 2. The internal properties of the objects that need to be generated are mutually dependent on each other.

  • Note: The difference from the factory mode is that the builder mode is more concerned with the order of assembly of parts.
    write picture description here

  • Builder Pattern: Separating the construction of a complex object from its representation, allowing the same construction process to create different representations. The Builder pattern is an object creation pattern.
  • The builder pattern creates a complex object step by step, it allows the user to build complex objects by specifying their type and content only, the user does not need to know the specific construction details inside.
    write picture description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325999506&siteId=291194637