Learning design patterns: creating design patterns

Posted by Ju-Pao on Mon, 17 Jan 2022 09:19:24 +0100

1, Singleton mode

1. Applicable scenarios

Only 1 object is required for the project

2. Advantages and disadvantages

&Advantages:

(1) Reduce memory expenses. For frequently used objects, they are always created and destroyed, which takes up a lot of memory
(2) Reduce the performance overhead. When the generation of an object requires more resources, it is time-consuming to generate an object

&Disadvantages:

(1) Cannot be inherited because the constructor is private
(2) In parallel development, if the class using singleton mode is not completed, it can not be self-test

Get to:
(1) stub and mock methods are often used in unit testing

2, Factory method model

The factory method pattern includes four role classes: abstract factory class, concrete factory class, abstract product class and concrete product class

1. Usage scenario

There is a product category that needs to frequently modify the code for creating specific products in a piece of code. At this time, you can use the factory mode to implement a specific factory class for each specific product.
be careful:
• it can be used in all places of new objects, but consider whether using factory classes for management will increase the complexity of the code
• factory method patterns can be used in heterogeneous projects

2. Example code:

UML class diagram is as follows:

The specific codes are as follows

package com.kk.factoryTest;
public interface Creator {
    /**
     * Create an abstract factory class for the product
     */
     <T extends Product> T create(Class<T> c);
}
package com.kk.factoryTest;
public class ConcreteCreator implements Creator{
    @Override
    public <T extends Product> T create(Class<T> c) {
        Product product = null;
        // It is also possible to use generics here
        T product1 = null;
        try {
            // Use class Forname (string classname), the return value is class <? > Do not know the type returned, and then create the corresponding instance of the class
            // newInstance() returns Object. Here, it is possible to convert Object to Product or not
            product = (Product) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}
package com.kk.factoryTest;
public interface Product {
    void method1();
}
package com.kk.factoryTest;
public class ConcreteProduct implements Product{
    @Override
    public void method1() {
        System.out.println("im concrete product");
    }
}

3. Factory mode, which is convenient to expand specific factory classes and reduce coupling.

3, Abstract factory pattern

1. Usage scenario

(1) The abstract factory mode is suitable for the case of multiple business types and multiple business products, for example:
A software needs to run on three different operating systems, which must comply with the configuration of each operating system, so there is a corresponding software category in each operating system, so it is in the abstract factory

public interface SoftwareCreateFactoryInteface {
    SoftwareWindow createInWindow();
    SoftwareMac createInMac();
    SoftwareAndroid createInAndroid(); 
}

(2) The abstract factory pattern is aimed at a family of products. If there is only one kind of products in the product family, the abstract method pattern will degenerate into the factory method pattern, and the responsibility is the abstract factory pattern.

2. Advantages and disadvantages

&Advantages

Within a product family, dependencies of different product classes can be encapsulated.

&Shortcomings

It is very difficult to extend the product family itself. If a new product class is added, the abstract factory class must be modified and the existing factory class must be affected.

3. Example code

(1) Code class diagram

(2) Get knowledge points:
• for the method of the parent class, the child class cannot inherit, so you can set the public method in the parent class. The child class implements this method, and the child class assigns a value to the parent class. The parent class calls this method, which also calls the method of the child class
• meaning of six arrows in UML: https://blog.csdn.net/qq_20936333/article/details/86773664

4, Builder mode

1. Meaning

(1) The creation and representation of a complex object are separated, so that the same construction process has different representations.
(2)
• the abstract builder defines the different components of the product class
• the director class defines the assembly sequence of different components, and the combination produces different objects

2. Usage scenario

The first: when the same method, different execution sequences and different results are produced, the builder mode can be used
Second: multiple components or parts can be assembled into one object;
The second kind: the product class is very complex, and the abstract builder is used to define the different composition of the product class;
The builder focuses on the part type and assembly process sequence

3. Advantages and disadvantages

&Advantages

• encapsulation, so that the client does not know the internal composition details of the product
• easy to expand, more parts can be added to form different products
• ease of detail risk control

4. Example code

(1) UML class diagram

(2) Code of each part

Computer.java
package com.kk.constructorDesign;
public abstract class Computer {
    private String type; // type
    private String cpu; // cpu
    private String ram; // Memory
    private String hardDisk; // Hard disk
    private String monitor; // monitor
    public String getMonitor() {
        return monitor;
    }
    public void setMonitor(String monitor) {
        this.monitor = monitor;
    }
    private String os; // operating system
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }
    public String getRam() {
        return ram;
    }
    public void setRam(String ram) {
        this.ram = ram;
    }
    public String getHardDisk() {
        return hardDisk;
    }
    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }
    public String getOs() {
        return os;
    }
    public void setOs(String os) {
        this.os = os;
    }
}

Type T410

package com.kk.constructorDesign;
/**
 * T401 Subclass
 */
public class T401 extends Computer{
    private String graphicCard;
    public T401() {
        // The subclass inherits all the methods of the parent class
        this.setType("ThinkPad T401");
    }
    public String getGraphicCard() {
        return graphicCard;
    }
    public void setGraphicCard(String graphicCard) {
        this.graphicCard = graphicCard;
    }
    @Override
    public String toString() {
        return "model:\t" + this.getType() + "\ncpu:\t" +
                this.getCpu() + "\n Memory:\t" + this.getRam() +
                "\n Hard disk:\t" + this.getHardDisk() + "\n Graphics card:\t" +
                this.getGraphicCard() + "\n monitor:\t" + this.getMonitor() +
                "\n operating system:\t" + this.getOs();
    }
}

Class X201

package com.kk.constructorDesign;
public class X201 extends Computer {
    public X201() {
        this.setType("ThinkPad X201");
    }
    @Override
    public String toString() {
        return "model:\t" + this.getType() + "\ncpu:\t" +
                this.getCpu() + "\n Memory:\t" + this.getRam() +
                "\n Hard disk:\t" + this.getHardDisk()  +
                "\n monitor:\t" + this.getMonitor() +
                "\n operating system:\t" + this.getOs();
    }
}
ComputerBuilder.class
package com.kk.constructorDesign;
public interface ComputerBuiler {
    void buildCpu();
    void buildRam();
    void buildHardDisk();
    void buildGraphicDisk();
    void buildMonitor();
    void buildOs();
    /**
     * Get the final production computer
     * @return
     */
    Computer getResult();
}

X201Builer.class

package com.kk.constructorDesign;
public class X201Builder implements ComputerBuiler {
    private X201 computer = new X201();
    @Override
    public void buildCpu() {
        computer.setCpu("i3-350");
    }
    @Override
    public void buildRam() {
        computer.setRam("2GB 1333MHz");
    }
    @Override
    public void buildHardDisk() {
        computer.setHardDisk("250GB 5400 turn");
    }
    @Override
    public void buildGraphicDisk() {
       //No graphics card
    }
    @Override
    public void buildMonitor() {
        computer.setMonitor("12 Inch 1280*800");
    }
    @Override
    public void buildOs() {
        computer.setOs("Windows7 Home edition");
    }
    @Override
    public Computer getResult() {
        return computer;
    }
}

T401Builder.class

package com.kk.constructorDesign;
public class T401Builder implements ComputerBuiler {
    private  T401 computer = new T401();
    @Override
    public void buildCpu() {
        computer.setCpu("i5-450");
    }
    @Override
    public void buildRam() {
        computer.setRam("4GB 1333MHz");
    }
    @Override
    public void buildHardDisk() {
        computer.setHardDisk("500GB 7200 turn");
    }
    @Override
    public void buildGraphicDisk() {
        computer.setGraphicCard("Nvidia NVS 3100M");
    }
    @Override
    public void buildMonitor() {
        computer.setMonitor("14 Inch 1280*800");
    }
    @Override
    public void buildOs() {
        computer.setOs("Windows 7 Flagship Edition");
    }
    @Override
    public Computer getResult() {
        return computer;
    }
}

Director.class

package com.kk.constructorDesign;
/**
 * The director class arranges the order in which computers are created
 */
public class Director {
    private ComputerBuiler builer;
    public Computer buildT401() {
        builer = new T401Builder();
        builer.buildCpu();
        builer.buildRam();
        builer.buildHardDisk();
        builer.buildGraphicDisk();
        builer.buildOs();
        builer.buildMonitor();
        return builer.getResult();
    }
    
    public Computer buildX201() {
        builer = new X201Builder();
        builer.buildCpu();
        builer.buildRam();
        builer.buildHardDisk();
        builer.buildOs();
        builer.buildMonitor();
        return builer.getResult();
    }
}

ComputerDirector.java

package com.kk.constructorDesign;
public class ComputerDirectorTest {
    public static void main(String[] args) {
        Director director = new Director();
        Computer t401 = director.buildT401();
        System.out.println(t401);
        Computer x201 = director.buildX201();
        System.out.println(x201);
    }
}

Final presentation results

5. Difference between and factory mode

Their processing methods are different. The factory mode is that specific factory classes decide how to create corresponding products
The builder mode is the specific construction class to realize the specified behavior, and the director class decides how to create the corresponding product

6.Get knowledge points

1. Can a Java subclass inherit the private variables and methods of its parent class?
After analyzing the memory, you will find that when a subclass is instantiated, by default, the constructor of the parent class will be called to initialize the parent class, that is, a parent class object will be created in memory, and then the unique attributes of the subclass will be placed outside the parent class object. The two together form a subclass object.
Therefore: it is right that a subclass inherits all the properties and methods of the parent class or that a subclass owns all the properties and methods of the parent class, but the private properties and methods of the parent class cannot be accessed directly by the subclass. That is, you just have it, but you can't use it. (Java reflection mechanism is not considered here)

5, Prototype mode

1. Advantages and disadvantages

&Advantages

(1) It directly copies the memory binary stream. When a large number of objects are needed, this method is better than the new object (because it copies the memory data directly, the speed will be faster);
(2) Evade the constraints of the constructor and will not execute the constructor

2. Example code

Prototype.class
package com.kk.prototypeDesign;
/**
 * Mark this interface for cloning
 */
public interface Prototype extends Cloneable{
    Prototype clone();
}
ConcretePrototype.class
package com.kk.prototypeDesign;
/**
 * Subclasses can also be clone d
 */
public class ConcretePrototype implements Prototype{
    @Override
    public Prototype clone() {
        try {
            // Object is called here Clone() method
           return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}
client Client.java
package com.kk.prototypeDesign;
/**
 * The requirement of the client class is to obtain the cloned object
 */
public class Client {
    public void operation(Prototype prototype) {
        Prototype cloneObject = prototype.clone();
    }
}

3. Usage scenario

(1) Resources are optimized. When class initialization consumes resources very much, this resource includes data and hardware resources;
(2) In the scenario of performance and security requirements, generating an object through new requires very cumbersome data preparation or access rights
(3) A scene where an object has many modifiers.
The prototype pattern usually appears together with the factory pattern. An object is created through the clone method, and then provided to the caller by the factory method.

4.Get knowledge points

(1) There is no method in the clonable interface. Why implement this interface? After implementing it, you can call object Clone() method
&Indicates that this class can be used for clone. Therefore, to implement the clonable interface, clone is not allowed without this tag
&You need JVM support, so you need to call object Clone () or super clone()
(2) The clone method provided by Object is a shallow copy, which only copies the reference of the Object and does not copy the data of the cloned Object. If you want to make a deep copy, you need to manually control the clone depth when overwriting the clone method.

Topics: Design Pattern