Sorting out 12 common design patterns and application scenarios in Java

Table of contents

singleton pattern

hungry man mode

lazy mode

thread lock mode

Double Judgment Mode

static inner class pattern

strategy pattern

factory pattern

simple factory

abstract factory

facade mode

decorator pattern

chain of responsibility model

Flyweight mode

Observer pattern

Proxy mode

static proxy mode

Dynamic Proxy Mode

adapter pattern

prototype pattern

template method pattern


singleton pattern

        Singleton mode is an old-fashioned design mode in java. I believe that everyone has come into contact with it at work. As far as I am concerned, the main application scenarios of singleton mode are as follows:

        It is suitable for scenarios where objects are frequently obtained in the project, such as: obtaining cache objects, obtaining some tool objects, etc., because these objects are used frequently, so when obtaining objects, we use the singleton mode to specify to obtain an object.

The following editor will take you to review the writing method of the singleton mode again. Here we will introduce the five writing methods of the singleton mode .

hungry man mode

 The code structure is as follows:

  1. private static final object direct new
  2. private no-argument constructor
  3. public static instance method

        Hungry man mode is one of the commonly used writing methods in singleton mode. The main feature is to directly create an object when defining an object. The detailed code is as follows:

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 单例模式 饿汉式
 *  上来就new对象
 **/
public class SignletonHungry {

    //1. 私有的静态的最终的对象
    private static final SignletonHungry singl=new SignletonHungry();

    //2. 私有的无参构造函数
    private SignletonHungry(){

    }

    //3. 公共的静态的实例方法
    public static SignletonHungry getInstance(){
        return singl;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonHungry.getInstance().hashCode());
            }).start();
        }
    }
}

        Below the class, we define a test method to simulate and verify whether the hashcode method of the object obtained through the singleton class is consistent each time during multi-threaded concurrent access. If it is consistent, it means thread safety. The execution results are as follows:

It can be seen that the execution results are consistent. This kind of hungry Chinese writing method is generally used the most in actual projects.

Advantages: This way of writing is relatively simple, that is, the instantiation is completed when the class is loaded, which avoids the problem of thread synchronization.

Disadvantages: But because the object is initialized when the object is specified, when the class is relatively large, it will also cause a certain amount of resource consumption.

lazy mode

The code structure is as follows:

  1. Private static objects are empty and not new
  2. private no-argument constructor
  3. public static instance method

        In order to avoid the above-mentioned shortcomings of the hungry man style, the lazy man style singleton writing method is extended. When defining the object, the initialization is not performed directly. In the actual instantiation method, the initialization operation is performed, which saves Certain resources, the specific implementation code is as follows:

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *
 * 单例模式 懒汉式
 * 调用实例方法时才new对象
 * 节省空间 缺点是线程不安全
 **/
public class SignletonFull {

    //1. 私有的静态的对象 先不new 默认为null值
    private static SignletonFull signletonFull;

    //2. 私有的无参构造器
    private SignletonFull(){}

    //3. 公共的静态的方法
    public static SignletonFull getInstance() throws InterruptedException {
        if(signletonFull==null){
            Thread.sleep(1000);
            signletonFull=new SignletonFull();
        }
        return signletonFull;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                try {
                    System.out.println("获取的hashCode是: "+SignletonFull.getInstance().hashCode());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

        Similarly, under this class, we also define a test method to simulate and verify whether the hashcode method of the object obtained through the singleton class is consistent each time during multi-threaded concurrent access. If it is consistent, it means thread safety. Execution results as follows:

        We can see that the lazy man mode has on-site safety problems when multi-threaded concurrent acquisition of singleton classes, so since there are thread safety problems, how can we improve this problem? See Thread Lock Mode.

thread lock mode

 The code structure is as follows:

  1. Private static objects are empty and not new
  2. private no-argument constructor
  3. Shared static instance method, add synchronize modification when judging whether the object is empty

        Thread locks can be used to solve the thread safety problems in the lazy man mode. The specific implementation code is as follows:

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *
 * 单例模式之 加锁
 * 线程安全 缺点是效率低 受synchronized锁升级的影响
 **/
public class SignletonThread {
    //1. 私有的静态的对象
    private static SignletonThread signletonThread;

    //2. 私有的构造方法
    private SignletonThread(){}

    //3. 公共的静态的实例方法 在if里面加上锁synchronized
    public static SignletonThread getInstance(){
        if (signletonThread==null){
            synchronized (SignletonThread.class){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                signletonThread=new SignletonThread();
            }
        }
        return signletonThread;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonThread.getInstance().hashCode());
            }).start();
        }
    }
}

        Similarly, under this class, we also define a test method to simulate and verify whether the hashcode method of the object obtained through the singleton class is consistent each time during multi-threaded concurrent access. If it is consistent, it means thread safety. Execution results as follows: 

         We can see that the execution result is not satisfactory. Why? This is because when the synchronized code is executed fast, some threads have already obtained the object, which leads to the inconsistency of the obtained objects. So how to solve this problem?

Double Judgment Mode

The code structure is as follows:

  1. Private static objects are empty and not new
  2. private no-argument constructor
  3. Shared static instance method, add synchronize modification when judging whether the object is empty
  4. In the judgment, judge whether it is empty again
package designmodel.signelton;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *
 * 单例写法
 * 双重判断式
 **/
public class SignletonThreadTwo {

    //1. 私有的静态的对象
    private static SignletonThreadTwo signletonThreadTwo;

    //2. 私有的构造方法
    private SignletonThreadTwo(){}

    //3. 公共的静态的实例方法 在if里面加上锁synchronized 在锁块中继续判断是否为空
    public static SignletonThreadTwo getInstance(){
        if (signletonThreadTwo==null){
            synchronized (SignletonThreadTwo.class){
                if(signletonThreadTwo==null){
                    signletonThreadTwo=new SignletonThreadTwo();
                }
            }
        }
        return signletonThreadTwo;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonThreadTwo.getInstance().hashCode());
            }).start();
        }
    }
}

        Similarly, under this class, we also define a test method to simulate and verify whether the hashcode method of the object obtained through the singleton class is consistent each time during multi-threaded concurrent access. If it is consistent, it means thread safety. Execution results as follows:  

        Let's look at the execution results. Although the execution results are what we want, due to the introduction of synchronized code blocks, the concepts of lightweight locks and heavyweight locks are also introduced. Although thread safety is guaranteed, performance bonuses are lost. And it is easy to cause deadlock, so is there any way to be thread-safe and efficient? 

static inner class pattern

The code structure is as follows:

  1. private no-argument constructor
  2. private static inner class
  3. Define a private final static object in the inner class, a new one
  4. Define a public instance method that returns an inner class. Object
package designmodel.signelton;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 单例模式
 * 通过静态内部类实现懒加载与线程安全
 * 利用JVN特性实现 JVM在加载类和内部类的时候 只会在运行的时候加载一次 从而保证线程安全和懒加载
 **/
public class SignletonStaticClass {

    //1. 私有的无参构造器
    private SignletonStaticClass(){}

    //2. 私有的静态的内部类
    private static class SignletonStatic{
        //3. 在私有的内部类中定义私有的 最终的 静态的对象
        private final static SignletonStaticClass signletonStaticClass=new SignletonStaticClass();
    }

    //4. 公共的静态的实例方法
    public static SignletonStaticClass getInstance(){
        return SignletonStatic.signletonStaticClass;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonStaticClass.getInstance().hashCode());
            }).start();
        }
    }

}

        When executing the verification code, we can see that thread safety and efficiency are guaranteed through this writing method. The principle of this writing method is similar to the hungry Chinese style. Using the JVN feature to realize that the JVM will only load classes and internal classes when they are running. Load once to ensure thread safety and lazy loading.

strategy pattern

The code structure is as follows:

  1. Define the strategy interface and define common methods.
  2. Define N implementation classes, implement the interface, and re-method.
  3. Define the Context context class and use polymorphism for encapsulation.
  4. When used, it is called through the Context context class, and the object of the implementation class is passed in the constructor.

     Strategy pattern: The strategy pattern is a behavioral pattern that separates objects from behaviors and defines behaviors as a behavioral interface and the implementation of specific behaviors. The biggest feature of the strategy pattern is the change of behavior, which can be replaced with each other. Each if judgment can be understood as a strategy, which can make the algorithm change independently of the user who uses it.

    scenes to be used:

                       1. Assume that a supermarket now has three levels of members, ordinary members, VIP1, and VIP2.

                       2. At the time of checkout, if three registered members purchased the same item, no discount will be given to ordinary members, 10% off to VIP1, and 20% off to VIP2

Define the strategy interface:

package designmodel.celve;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 12:20 2022/11/8
 * @Param 
 * @return
 * 定义策略接口
 * 案例场景:
 *  有三种会员 购买相同数量和单价的产品时 需要打不同的折扣
 **/
public interface StrategyInt {

    //price价格 n数量
    public double getPrice(double price,int n);
}

Define ordinary members and implement the strategy interface:

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 实现类1 实现接口中定义的计算价格方法
 * 普通会员类 不打折
 **/
public class NormalPerson implements StrategyInt {

    //普通会员不打折
    @Override
    public double getPrice(double price, int n)
    {
        System.out.println("普通会员不打折.....");
        return (price*n);
    }
}

 Define the vip1 member and implement the strategy interface:

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *实现类2 实现接口中定义的计算价格方法
 *VIP1会员 打9折
 **/
public class Vip1Person implements StrategyInt{

    //VIP1客户 打9折
    @Override
    public double getPrice(double price, int n) {
        System.out.println("VIP1打9折.....");
        return (price*n)*0.9;
    }
}

 Define vip2 membership and implement the strategy interface: 

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 实现类2 实现接口中定义的计算价格方法
 * VIP2会员类 打8折
 **/
public class Vip2Person implements StrategyInt {

    @Override
    public double getPrice(double price, int n) {
        System.out.println("VIP2打8折.....");
        return (price*n)*0.8;
    }
}

Define the context context class and use polymorphism for encapsulation: 

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 上下文类 对实现类和接口进行封装
 **/
public class PersonContext {
    //1. 定义私有对象
    private StrategyInt strategyInt;

    //2. 定义有参构造方法
    public PersonContext(StrategyInt strategyInt) {
        this.strategyInt = strategyInt;
    }

    //3. 定义计算价格的方法
    public double getPrice(double price,int n){
        return strategyInt.getPrice( price, n);
    }


}

Define the test class and call the method:

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类  演示策略模式的使用场景
 **/
public class StrategyTest {

    public static void main(String[] args) {
        //定义三个类型的对象
        NormalPerson normalPerson = new NormalPerson();
        Vip1Person vip1Person = new Vip1Person();
        Vip2Person vip2Person = new Vip2Person();
        //new context类对象 将三个类型的对象传入
        PersonContext npersonContext = new PersonContext(normalPerson);
        PersonContext v1personContext = new PersonContext(vip1Person);
        PersonContext v2personContext = new PersonContext(vip2Person);
        //利用多态 通过调用context类对象的计算价格方法 实际上调用的子类的计算价格方法 得到最终价格
        System.out.println("普通会员: "+npersonContext.getPrice(300,20));
        System.out.println("VIP1: "+v1personContext.getPrice(300,20));
        System.out.println("VIP2: "+v2personContext.getPrice(300,20));
    }
}

The execution results are as follows:

 

factory pattern

        I believe that everyone has used the factory pattern a lot. This type of design pattern belongs to the creation pattern, which provides the best way to create objects. In the factory pattern, we will not expose the creation logic to the client when creating objects , and by using a common interface to point to the newly created object.

       The factory method pattern can be used wherever complex objects need to be generated. One thing to note is that complex objects are suitable for using the factory pattern, while simple objects, especially objects that only need to pass new a few times, are not used. In this case, there is no 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.

simple factory

        Simple factory is a simple way of writing the factory pattern. This way of writing is relatively simple, but it also brings coupling problems. Let's define airplanes and cars and the factory classes that produce them. The main implementation code is as follows:

Aircraft:

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 飞机类
 **/
public class Plane {
    public void go(){
        System.out.println("飞机嗖嗖嗖....");
    }
}

Car class:

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 汽车类
 **/
public class Car {
    public void go(){
        System.out.println("汽车滴滴滴....");
    }
}

Factory class that produces vehicles:

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 工厂类
 **/
public class ProductFactory {

    public Car getCar(){
        return new Car();
    }

    public Plane getPlane(){
        return new Plane();
    }
}

Test class: 

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestClass {

    public static void main(String[] args) {
        Car car = new ProductFactory().getCar();
        Plane plane = new ProductFactory().getPlane();
        car.go();
        plane.go();
    }
}

The execution results are as follows:

 

        The writing method of this simple factory is relatively simple and convenient, but the disadvantage is also obvious, that is, the degree of coupling of the defined classes is too high. If new objects are added later, the factory class needs to be modified many times. How to solve this shortcoming? See the abstract factory pattern.

abstract factory

Application scenarios:

  • Decoupling : Separating responsibilities, separating the process of creating and using complex objects .
  • Reuse code to reduce maintenance costs: If the object creation is complex and needs to be used in multiple places, if it is written in each place , a lot of repeated code will be repeated. If the business logic changes , it needs to be modified everywhere; use the factory mode For unified creation, you only need to modify the factory class to reduce costs. 

The code structure is as follows:

      Take new energy vehicles as an example, Wuling and Tesla.

  1. Define the car interface, and some methods are defined in the car interface, such as start, run, and close.
  2. Define the car classes of Tesla and Wuling, and override these methods of the car interface.
  3. Define the factory interface for producing cars. There are methods for producing cars in the interface, and the return value type is the car interface.
  4. Define the factory classes of Tesla and Wuling respectively, implement the factory interface for producing cars, and rewrite the methods for producing cars.
  5. In the test class, directly new the factory classes of Wuling and Tesla, produce related products, and call the start, run, and shutdown methods.

Define the car interface:

package designmodel.factory.abstractfactory;
/**
 * @Author luocong
 * @Description //TODO
 * @Date 19:35 2022/11/8
 * @Param 
 * @return
 * 定义汽车的接口 汽车可以启动、跑、关闭
 **/
public interface CarProduct {
    //启动
    void start();
    //跑
    void run();
    //关闭
    void shutDown();
}

 Define the Tesla car class and implement the car interface:

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义具体的实现类
 * 特斯拉汽车
 **/
public class TeslaCar implements CarProduct {
    @Override
    public void start() {
        System.out.println("特斯拉启动了");
    }

    @Override
    public void run() {
        System.out.println("特斯拉跑了");
    }

    @Override
    public void shutDown() {
        System.out.println("特斯拉关闭了");
    }
}

Define the Wuling automobile class to implement the automobile interface:

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义具体的实现类
 * 五菱汽车
 **/
public class WulingCar implements CarProduct {
    @Override
    public void start() {
        System.out.println("五菱启动了");
    }

    @Override
    public void run() {
        System.out.println("五菱开始跑了");
    }

    @Override
    public void shutDown() {
        System.out.println("五菱关闭了");
    }
}

Define a factory class that produces cars: 

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义生产汽车的工厂类
 *
 **/
public interface CarproductFactory {

    CarProduct productCar();
}

Define the factory class that produces Wuling Motors: 

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义生产五菱的汽车工厂
 * 生成五菱汽车的对象
 **/
public class WuLingFactory implements CarproductFactory {
    @Override
    public CarProduct productCar() {
        return new WulingCar();
    }
}

Define the factory class that produces Tesla:

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义特斯拉汽车的工厂
 * 生产特斯拉汽车
 **/
public class TeslaFactory implements CarproductFactory {
    @Override
    public CarProduct productCar() {
        return new TeslaCar();
    }
}

Test class: 

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TestFactory {

    public static void main(String[] args) {
        //生产五菱汽车
        WuLingFactory wuLingFactory = new WuLingFactory();
        CarProduct carProduct = wuLingFactory.productCar();
        carProduct.start();
        carProduct.run();
        carProduct.shutDown();
        System.out.println("*******************************");
        //生产特斯拉汽车
        TeslaFactory teslaFactory = new TeslaFactory();
        CarProduct carProduct1 = teslaFactory.productCar();
        carProduct1.start();
        carProduct1.run();
        carProduct1.shutDown();
    }
}

   The execution results are as follows:

        Through the abstract factory, we can reduce the coupling between codes. For example, if we add the Xiaopeng car class in the future, we can directly add the factory class of the Xiaopeng car class and the Xiaopeng car class. This implementation method is beneficial to the business. expand.

facade mode

        Facade Pattern: Also called Appearance Pattern, it is required that the communication between the outside of a subsystem and its inside must be carried out through a unified object. The Facade pattern provides a high-level interface that makes the subsystem easier to use.

Applicable scene:

        There is a strong dependency relationship between multiple subsystem classes, and the invocation of complex relationships is handled uniformly through the facade class. When the external class is called, the facade class can be called without calling the subsystem class.

 The facade mode is relatively simple, and the code implementation is as follows:

Define system class A, and communicate with system A through class A:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟系统类A
 * 假设A系统类中有方法doA
 **/
public class SystemA {
    public String doA(){
        return "A";
    }
}

Define system class B, and communicate with system A through class B:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟系统类B
 * 假设A系统类中有方法doB
 **/
public class SystemB {
    public String doB(){
        return "B";
    }
}

Define system C class, and communicate with system A through class C:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟系统类C
 * 假设A系统类中有方法doC
 **/
public class SystemC {
    public String doC(){
        return "C";
    }
}

Define the facade class, and realize the complex calls between the three systems A, B, and C through the facade class:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 门面模式中的门面类 可以通过此类实现系统A、B、C之间的复杂关系调用
 **/
public class ControlClas {

    //私有化三个系统的类
    private SystemA systemA=new SystemA();
    private SystemB systemB=new SystemB();
    private SystemC systemC=new SystemC();

    //通过此方法实现A、B、C之间的复杂调用
    public void doSomthing(){
        //自定义逻辑
        systemA.doA();
        //自定义逻辑
        systemB.doB();
        //自定义逻辑
        systemC.doC();
    }

}

         We can see that through the last control class, we can control the complex scene where the systems A, B, and C call each other, and when the external class calls A, B, and C to implement business, we can Directly call the facade class to implement, without defining complex codes in A, B, and C.

decorator pattern

        The decorator pattern is an object structural pattern that dynamically adds responsibilities/functions to objects in a way that does not require defining subclasses, and uses the association relationship between objects to replace the inheritance relationship between classes. 

 The application scenarios are as follows:

   for example:

       For example, Wuling Motors, Wuling Motors can run first, and this characteristic is an invariable characteristic.

       Other models are different, such as different battery life, whether it is convertible, whether it has intelligent voice, and so on.

       Interfaces can be defined for unchanging features, and decorators can be defined for changing features. Decorators add some modifications to the original.

The code structure is as follows:

  1. Define Wuling Motors abstract class, general method
  2. Define convertible version and gameboy version to inherit to Wuling Motors abstract class, and rewrite the general method.
  3. Define the decorator class of Wuling, inherit it from the abstract class of Wuling Auto, pass in the object of the abstract type of Wuling Auto, and call the general method of the abstract type of Wuling Auto.
  4. Define the convertible decorator and battery life enhancement decorator of Wuling Motors separately, inherit to the decorator class of Wuling Motors, rewrite the general method, and increase the decorator function.
  5. Through the test class call, the new Wuling convertible object is passed into the convertible decorator, and the run method of the decorator is called.

Define the abstract class of Wuling New Energy Vehicle and define the run method:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 五菱新能源汽车
 **/
public abstract class WulingNewEngeryCar {

    abstract void run();
}

Define the specific model of Wuling New Energy, such as gameboy, which is inherited from Wuling New Energy:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 五菱gameBoy
 **/
public class WulingGameBoy extends WulingNewEngeryCar {
    @Override
    void run() {
        System.out.println("五菱gameBoy");
    }
}

Define the specific model of Wuling New Energy, such as the convertible version, which is inherited to Wuling New Energy:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 五菱敞篷版
 **/
public class Wulingchangpeng  extends  WulingNewEngeryCar{
    @Override
    void run() {
        System.out.println("敞篷版五菱");
    }
}

 Define the decoration class of Wuling New Energy Vehicle, which also inherits from the new energy class:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义五菱汽车的装饰器类
 **/
public abstract class WulingDecorate extends WulingNewEngeryCar{
    //私有的对象
    private WulingNewEngeryCar wulingNewEngeryCar;
    //公共的构造函数
    public WulingDecorate(WulingNewEngeryCar wulingNewEngeryCar) {
        this.wulingNewEngeryCar = wulingNewEngeryCar;
    }
    //重写汽车的能力
    @Override
    void run() {
        wulingNewEngeryCar.run();
    }
}

Define the decoration class of Wuling Convertible, inherited from the decoration class of Wuling Automobile:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 敞篷装饰器
 **/
public class NoDoorDecorate extends WulingDecorate{

    //调用父类的构造方法
    public NoDoorDecorate(WulingNewEngeryCar wulingNewEngeryCar) {
        super(wulingNewEngeryCar);
    }

    //增加装饰
    @Override
    void run() {
        super.run();
        System.out.println("增加敞篷功能");
    }
}

Define the decoration class of Wuling battery life version, inherited from the decoration class of Wuling Motors:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 续航增强装饰器
 **/
public class RunLongDecorate extends WulingDecorate{
    public RunLongDecorate(WulingNewEngeryCar wulingNewEngeryCar) {
        super(wulingNewEngeryCar);
    }

    @Override
    void run() {
        super.run();
        System.out.println("续航增强");
    }

}

Test class:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class AppTestClass {
    public static void main(String[] args) {
        //new 一个wuling敞篷类
        Wulingchangpeng wulingchangpeng=new Wulingchangpeng();
        //调用敞篷装饰器 增加敞篷功能
        NoDoorDecorate noDoorDecorate = new NoDoorDecorate(wulingchangpeng);
        noDoorDecorate.run();
        RunLongDecorate runLongDecorate1 = new RunLongDecorate(wulingchangpeng);
        runLongDecorate1.run();
        System.out.println("*****************");
        WulingGameBoy wulingGameBoy = new WulingGameBoy();
        RunLongDecorate runLongDecorate = new RunLongDecorate(wulingGameBoy);
        runLongDecorate.run();
    }
}

The execution results are as follows:

        We can see that the advantage of the decorator mode is that it encapsulates the unchanging run method, and then enhances it based on the run method, so as to meet the needs of different ways of enhancing certain methods in different scenarios. If another model is added, then It only needs to add model classes and specific decorator classes, which greatly reduces the coupling of codes and at the same time satisfies the enhancement of methods.

chain of responsibility model

        The Chain of Responsibility design pattern is a common design pattern in software development. In this pattern, a request is processed progressively to form a chain, and the request is processed in the nodes of the chain. After a node processes its own logic, it is passed to the in the next node.

Application scenario:

         When dealing with the message information transmitted by the web page, the message information will be processed. Some classes are responsible for processing special characters in the message, and some classes are responsible for processing information such as sensitive words in the message. This situation is applicable in the chain of responsibility model.

The code structure is as follows:

  1. Define the parent class for filtering
  2. Define two subclasses to inherit from the parent class and rewrite the filtering method
  3. Define the chain of responsibility class, pass in the two subclasses, and call the filter method of the subclasses.
  4. Pass the subclass through the test class, calling the filter method.

 Define an interface for handling messages:

package designmodel.responsiblity;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 11:06 2022/11/9
 * @Param 
 * @return
 * 定义处理消息的接口
 **/
public interface FatherFilter {
    //定义处理消息的方法
    public String doFilter(String msg);
}

Define a class for filtering special characters and implement an interface for processing messages:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 处理http消息的类
 * 过滤http消息
 **/
public class HttpFilter implements FatherFilter{

    @Override
    public String doFilter(String msg) {
        String replace = msg.replace("-", "");
        System.out.println("HttpFilter replace msg: "+replace);
        return replace;
    }
}

Define the class that handles sensitive words and implement the interface for processing messages:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 处理消息的类
 * 过滤消息
 **/
public class MsgFilter implements FatherFilter{

    @Override
    public String doFilter(String msg) {
        String replace = msg.replace("*", "");
        System.out.println("MsgFilter replace msg: "+replace);
        return replace;
    }
}

        Define the chain of responsibility base class, define the collection, and store the objects whose generic type is the message interface in the collection. When calling the chain of responsibility class, loop the collection and call the object point filter method:

package designmodel.responsiblity;

import java.util.ArrayList;
import java.util.List;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 责任链基类
 **/
public class FatherFilterChain {

    //储存http和msg的filter
    List<FatherFilter> list=new ArrayList<FatherFilter>();

    //添加filter
    public void add(FatherFilter fatherFilter){
        list.add(fatherFilter);
    }

    //定义执行过滤的方法
    public void doFilter(String msg){
        for (int i = 0; i < list.size(); i++) {
            msg = list.get(i).doFilter(msg);

        }
    }


}

Define the message class and store the message:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟传递消息的类
 **/
public class Msg {
    private String msg;

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }
}

Test class:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestResponsiblity {

    public static void main(String[] args) {
        //定义消息类
        Msg msg = new Msg();
        msg.setMsg("你好,------,我是***琪琪.....");
        //new http处理对象和msg处理对象
        HttpFilter httpFilter = new HttpFilter();
        MsgFilter msgFilter = new MsgFilter();
        //new 责任链处理对象
        FatherFilterChain fatherFilterChain = new FatherFilterChain();
        //将http处理对象和msg处理对象加入责任链
        fatherFilterChain.add(httpFilter);
        fatherFilterChain.add(msgFilter);
        //传递消息 执行过滤
        fatherFilterChain.doFilter(msg.getMsg());

    }
}

The execution results are as follows:

         We can see that the so-called Chain of Responsibility pattern, to put it bluntly, uses the characteristics of polymorphism, encapsulates objects into collections, and calls the method of the object in a loop when calling a method, and uses the loop to call. The typical application scenario of the Chain of Responsibility pattern is The filter class of spring, if you are interested, you can look at the source code.

Flyweight mode

        Flyweight mode:  By sharing existing objects, the number of objects that need to be created is greatly reduced, and the overhead of a large number of similar objects is avoided, thereby improving the utilization rate of system resources, and recurring content is taken out as a shared part and shared by multiple objects One copy, thus reducing the pressure on memory

Application scenario:

        The implementation of String is Flyweight mode. There is a constant pool for various characters at the bottom layer. When a variable refers to a constant, it directly refers to the constant in the constant pool. Another example is the database connection pool, which also uses the Flyweight mode.

Let's look at the code implementation of the simulated database connection:

Define the database connection resource base class Other classes need to inherit this class:

package designmodel.enjoymodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义数据库连接资源基类 其他类需要继承此类
 **/
public abstract class DataSource {
    String dataId;
    String dataName;

    public String getDataId() {
        return dataId;
    }

    public String getDataName() {
        return dataName;
    }

    public void setDataId(String dataId) {
        this.dataId = dataId;
    }

    public void setDataName(String dataName) {
        this.dataName = dataName;
    }

    public DataSource(String dataId, String dataName) {
        this.dataId = dataId;
        this.dataName = dataName;
    }
    public abstract void method();

    @Override
    public String toString() {
        return "DataSource{" +
                "dataId='" + dataId + '\'' +
                ", dataName='" + dataName + '\'' +
                '}';
    }
}

Define the database object producer class:

package designmodel.enjoymodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 数据库连接生产者类1
 **/
public class DataSourceMaker extends DataSource{

    public DataSourceMaker(String dataId, String dataName) {
        super(dataId, dataName);
    }

    @Override
    public void method() {
        System.out.println("使用DataSourceMaker1生产数据库连接对象.....");
    }
}

Define the factory class to produce database connection objects:

package designmodel.enjoymodel;

import java.util.HashMap;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 数据库连接工厂 生产数据库连接对象
 *
 **/
public class DataSourceFactory {
    private static HashMap<String,DataSource> hashMap=new HashMap<>();

    public DataSourceFactory() {
        for (int i = 0; i < 10; i++) {
            DataSourceMaker dataSourceMaker = new DataSourceMaker(String.valueOf(i), "DataSource" + i);
            hashMap.put(dataSourceMaker.getDataId(),dataSourceMaker);
        }
    }



    public DataSource getDataSourceFactory(String datasourceName){
        if (hashMap.containsKey(datasourceName)){
            return hashMap.get(datasourceName);
        }
        return null;
    }
}

Define the test class:

package designmodel.enjoymodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TestDataSource {

    public static void main(String[] args) {
        //取出数据库连接对象
        DataSourceFactory dataSourceFactory = new DataSourceFactory();
        for (int i = 0; i < 10; i++) {
            System.out.println("i: "+dataSourceFactory.getDataSourceFactory(String.valueOf(i)).toString());
        }
    }
}

The execution results are as follows:

 

         It can be seen that the main purpose of the Flyweight pattern is to build the concept of a pool. When you need to use the object, you can get it from the pool. You don’t need to create the object multiple times. You can see it in the implementation of the database connection pool.

Observer pattern

        Observer mode (Observer) , also known as publish-subscribe mode (Publish/Subscribe) , defines a one-to-many dependency relationship (registration) between objects, so that whenever an object changes state, all objects that depend on it will Get notified and automatically updated (notifications). To put it bluntly, it is a process of registration and notification.

The code structure is as follows:

  1. Define the observer interface and observer methods.
  2. Define the implementation classes A and B of the interface
  3. Define the theme class and pass the observer into a collection
  4. Call the notification method, loop the observer, and pass parameters to the observer to respond.

        The following code is used to simulate the movement between hot money and funds when the stock market is changing. This scene can vividly show the observer mode:

Define the stock market watcher interface:

package designmodel.watcher;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 12:01 2022/11/9
 * @Param 
 * @return
 * 定义股票观察者父类
 **/
public interface SharsObserver {

    //观察之后做出如何反映
    public void response(int i);
}

Define the hot money class and implement the observer interface:

package designmodel.watcher;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 个人股民
 **/
public class PersonObserver implements SharsObserver{
    @Override
    public void response(int i) {
        if(i>0){
            System.out.println("游资: 涨了,快点投资投资.......");
        }else{
            System.out.println("游资: 跌了,快点撤资撤资.......");
        }
    }
}

Define the fund class and implement the observer interface:

package designmodel.watcher;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class CompanyObserver implements SharsObserver {
    @Override
    public void response(int i) {
        if(i>0){
            System.out.println("机构: 涨了,再拉点投资吧.......");
        }else{
            System.out.println("机构: 跌了,稳一点,先不动.......");
        }

    }
}

 Define the subject class to assemble the observer's dynamics together:

package designmodel.watcher;

import designmodel.responsiblity.FatherFilter;

import java.util.ArrayList;
import java.util.List;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义主题类型
 * 其中定义可以新增删除 通知观察者的方法
 **/
public class Subject {

    //储存游资和基金的对象
    List<SharsObserver> list=new ArrayList<SharsObserver>();

    //新增观察者
    public void addObserver(SharsObserver sharsObserver){
        list.add(sharsObserver);
    }

    //通知观察者
    public void change(int j){
        for (int i = 0; i < list.size(); i++) {
            SharsObserver sharsObserver = list.get(i);
            sharsObserver.response(j);
        }
    }
}

Test class:

package designmodel.watcher;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestMain {

    public static void main(String[] args) {
        CompanyObserver companyObserver = new CompanyObserver();
        PersonObserver personObserver = new PersonObserver();
        Subject subject = new Subject();
        subject.addObserver(companyObserver);
        subject.addObserver(personObserver);
        subject.change(2);
        System.out.println("---------------------");
        subject.change(0);

    }
}

The execution results are as follows:

 

         As you can see from the code, the observer pattern is similar to the chain of responsibility pattern, so the observer pattern is generally used in conjunction with the chain of responsibility pattern.

Proxy mode

        The proxy mode is a commonly used java design mode. Its characteristic is that the proxy class has the same interface as the delegate class. The proxy class is mainly responsible for preprocessing messages for the delegate class, filtering messages, forwarding messages to the delegate class, and processing messages after the event.

static proxy mode

        Static proxy is a mode of implementing the proxy process through a custom class. It can only proxy this class. If you want to proxy other classes, you need to write a new proxy method if you want to proxy other classes.

The code structure is as follows:

  1. Define car interface
  2. Define the implementation class of the car interface to realize the car interface.
  3. Define the proxy class of the car and implement the car interface.
  4. Inject the object of the interface type in the proxy class, call the run method, and realize the call of the new method before and after the run method

Define the car interface:

package designmodel.poxymodel.staticpoxy;
/***
 * @Author luocong
 * @Description //TODO
 * @Date 17:02 2022/11/9
 * @Param 
 * @return
 * 定义汽车类
 **/
public interface CarInterface {
    //汽车可以跑
    public void run();
}

Define the car class and implement the car interface:

package designmodel.poxymodel.staticpoxy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class Car implements CarInterface {

    @Override
    public void run() {
        System.out.println("汽车在跑.......");
    }
}

Define the proxy class of the car and also implement the car interface:

package designmodel.poxymodel.staticpoxy;

import designmodel.poxymodel.staticpoxy.Car;
import designmodel.poxymodel.staticpoxy.CarInterface;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义汽车的代理对象 代理对象也实现汽车接口
 **/
public class Carproxy  implements CarInterface {
    //私有化汽车类
    private Car car;
    //创建构造函数
    public Carproxy(Car car) {
        this.car = car;
    }
    //调用汽车类的run方法 在run之前和之后可以定义新方法
    @Override
    public void run() {
        beforeRun();
        car.run();
        afterRun();
    }

    //汽车运行之前调用的方法
    private void afterRun() {
        System.out.println("汽车打开火了.....");
    }

    //汽车运行之后调用的方法
    private void beforeRun() {
        System.out.println("汽车熄火了.....");
    }
}

Test class: 

package designmodel.poxymodel.staticpoxy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestMain {
    public static void main(String[] args) {
        Carproxy carproxy = new Carproxy(new Car());
        carproxy.run();
    }
}

Results of the:

 

        Through static proxy, we can simply realize the proxy of a certain class and interface, but static proxy also has certain limitations. If we need to proxy a new class, we need the proxy class to implement a new interface to rewrite Some methods, this is obviously inconvenient, so JDK provides us with a dynamic proxy method.

Dynamic Proxy Mode

        Dynamic proxy is implemented by JDK for us. Its principle is based on class reflection, dynamically generates a proxy class for us, and helps us execute methods. We can define some custom methods before and after the method is executed. Let’s look at it below Code structure:

  1. Define car interface
  2. Define the implementation class of the car interface to realize the car interface.
  3. Define the proxy class, inject the object of the interface type, call the newProxyInstence method of the Proxy, pass in the object.getclass.getclassloader, pass in the object.getClass.getInterfaces, pass in the internal class InvocationHandler, and implement the call in the internal class.

Define the car interface:

package designmodel.poxymodel.movepoxy;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 17:15 2022/11/9
 * @Param
 * @return
 * 定义汽车接口
 **/
public interface CarInterface {
    public void run();
}

Define the car class and implement the interface:

package designmodel.poxymodel.movepoxy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 汽车类实现了汽车接口 重写run方法
 **/
public class Car  implements CarInterface{

    @Override
    public void run() {
        System.out.println("汽车跑起来了......");
    }
}

Define the proxy class of the car class (it can also be implemented directly in the test class, the main function is to encapsulate the proxy process):

package designmodel.poxymodel.movepoxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义汽车的动态代理类
 **/
public class CarMoveProxy {


    //利用JDK的动态代理实现代理模式
    public void doRun(Car car,InvocationHandler invocationHandler){
        //第一个参数 对象.getClass.getClassLoder 第二个参数 对象.getCalss.getInterfaces 第三个参数 invocationHandler内部类
        CarInterface car1= (CarInterface) Proxy.newProxyInstance(car.getClass().getClassLoader(),
                car.getClass().getInterfaces(),
                invocationHandler);
        car1.run();
    }
}

Test class:

package designmodel.poxymodel.movepoxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestProxy {
    public static void main(String[] args) {
        CarMoveProxy carMoveProxy = new CarMoveProxy();
        Car car = new Car();
        carMoveProxy.doRun(car, new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("汽车启动...");
                Object invoke = method.invoke(car, objects);
                System.out.println("汽车关闭...");
                return invoke;
            }
        });
    }
}

The execution results are as follows:

 

        The execution result is the same as that of the static proxy, but we can understand it through the code. The only difference is that the dynamic proxy does not require us to customize the proxy class. The second is that a proxy class is dynamically generated for us through the java reflection mechanism to execute our definition. method.

adapter pattern

        Convert the interface of a class to another interface that the client wants. The Adapter pattern enables classes that would otherwise not work together due to incompatible interfaces to work together

        The so-called adapter is to assemble different types of interfaces together in a certain way. For example, the data line converter we encounter in our life can convert different types of interfaces into the interfaces we need. The adapter mode is generally applied to new and old projects. In the case of coexistence, the codes of different writing methods in the new and old projects can be converted.

object adapter pattern

 Inject the object and complete the adapter conversion. The code structure is as follows: 

  1. Define interface TYPEC
  2. Define class TYPEA
  3. Define the adapter class and implement the interface TYPEC
  4. Populate the object of TypeA as an attribute, and rewrite the method of the interface
  5. The method of typeA can be called in the method of the interface

Define the typC interface:

package designmodel.adapter.objectadapter;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 18:04 2022/11/9
 * @Param 
 * @return
 * 定义typeC接口
 **/
public interface TypeCInterface {

    //输出5V的电压
    public void v5();
}

Define typeA class:

package designmodel.adapter.objectadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TypeA {
    public void v220(){
        System.out.println("输出220V电压");
    }
}

Define the adapter class, implement the typeC interface, and inject the TypeA object:

package designmodel.adapter.objectadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义适配器类 实现typeC接口
 **/
public class PowerAdapter implements TypeCInterface{

    public TypeA typeA=new TypeA();

    public PowerAdapter(TypeA typeA) {
        this.typeA = typeA;
    }

    @Override
    public void v5() {
        typeA.v220();
    }
}

Test class:

package designmodel.adapter.objectadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TestAdapter {
    public static void main(String[] args) {
        PowerAdapter powerAdapter = new PowerAdapter(new TypeA());
        powerAdapter.v5();
    }
}

Results of the:

         It can be seen that due to the injection of the typA object, when calling the method of v5, it should output 5V voltage, but now we can output 220V voltage, which is the adapter mode of the object.

class adapter pattern

Use inheritance and implementation to complete the conversion of the adapter, the code structure is as follows:

  1. define interfaceA
  2. define class B
  3. Define adapter class C to inherit from B to implement interface A
  4. In the adapter class, both the method of interface A and the method of class B can be rewritten

Define the TypeC interface:

package designmodel.adapter.classadapter;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 18:04 2022/11/9
 * @Param 
 * @return
 * 定义typeC接口
 **/
public interface TypeCInterface {

    //输出5V的电压
    public void v5();
}

Define typeA class:

package designmodel.adapter.classadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TypeA {
    public void v220(){
        System.out.println("输出220V电压");
    }
}

Define the adapter class:

package designmodel.adapter.classadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义类适配器 实现接口并继承类 在重写的方法中可以输出220v电压
 * 并且可以定义输出5v电压的逻辑
 **/
public class PowerAdapter extends TypeA implements TypeCInterface{
    @Override
    public void v5() {
        this.v220();
    }

    @Override
    public void v220() {
        super.v220();
    }
}

        It can be seen that the biggest difference between these two implementation modes is that one is to inject objects to implement interfaces, and the other is to inherit classes to implement interfaces. In the process of use, the first method is generally recommended. Inheritance will increase the burden to a certain extent. Coupling between classes. 

prototype pattern

        Prototype mode (Prototype mode) refers to: use the prototype instance to specify the type of object to be created, and create new objects by copying these prototypes, and the copy is divided into shallow copy and deep copy.

        The so-called shallow copy is to copy an object into another object, but the properties in the object point to the same. If any object is changed, the properties of the two objects will change accordingly.

        The deep copy is to use the IO stream to copy an object. When modifying the properties of any object, the properties of another object will not change.

Applicable scene:

        require extensive use of an object

The implementation structure of shallow copy is as follows:

  1. Define the Wukong class, define attributes, construction methods, tostring methods, and implement the cloneable interface
  2. Call the super.clone method to clone the object
  3. Modify object 2 at this time, and the properties of object 1 will change accordingly

The implementation structure of deep copy is as follows:

  1. Define the Wukong class, define attributes, construction methods, tostring methods, and implement the cloneable interface
  2. Writes the current object to the stream, and writes the object out again through the stream.
  3. Modify object 2 at this time. The properties of object 1 will not change accordingly.

The code for shallow copy is as follows:

package designmodel.prototype.shallowcopy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 猴王类 定义悟空的属性 重写克隆方法
 **/
public class KingMonkey implements Cloneable{
    private String name="孙悟空";
    private int age=5000;
    private String skill="七十二变";

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getSkill() {
        return skill;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public KingMonkey(String name, int age, String skill) {
        this.name = name;
        this.age = age;
        this.skill = skill;
    }

    public KingMonkey() {
    }

    @Override
    public String toString() {
        return "KingMonkey{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", skill='" + skill + '\'' +
                '}';
    }

    //重写clone方法
    @Override
    protected KingMonkey clone() throws CloneNotSupportedException {
        return (KingMonkey)super.clone();
    }
}

The code for deep copy is as follows:

package designmodel.prototype.deepcopy;


import java.io.*;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 新的猴王类 将param封装为自己的属性
 **/
public class KingMonkey1 implements Cloneable,Serializable{
    private String name="孙悟空";
    private int age=5000;
    private String skill="七十二变";

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getSkill() {
        return skill;
    }

    @Override
    public String toString() {
        return "KingMonkey1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", skill='" + skill + '\'' +
                '}';
    }

    public KingMonkey1() {
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            //将对象写入字节流
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            //把字节流转化为对象
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            System.out.println("走进来了.....");
            KingMonkey1 kingMonkey1 = (KingMonkey1) ois.readObject();
            return kingMonkey1;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

template method pattern

Defines the skeleton         of an algorithm in an operation , deferring some steps to subclasses. Allows subclasses to redefine some specific steps of an algorithm without changing the structure of the algorithm.

Application scenario:

        For example, to generate a PDF template, there are fixed logo positions and table layouts. What is not fixed is data analysis. You can place the logo position and basic style in the parent class, and place the data analysis in the subclass.

The code structure is as follows:

  1. Define an abstract parent class, define attributes and methods in it, and encapsulate the unchanged format.
  2. Define a subclass, inherit the parent class, rewrite some methods, add your own logic, call the total method of the parent class, and complete the processing.
  3. Define the test class, and complete the logic by calling the method of the parent class through the subclass

Define a template class:

package designmodel.templeteModel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模板类
 **/
public abstract class TempleteClass {
    //基本方法
    protected abstract void doA();
    protected abstract void doB();

    //模板方法
    public void templeteMethod(){
        doA();
        if(isDoAnything()){
            doB();
        }
    }
    //返回布尔值
    public boolean isDoAnything(){
        return true;
    }

}

Define the method implementation of the subclass:

package designmodel.templeteModel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *子类
 **/
public class TempleteChild extends TempleteClass{

    @Override
    protected void doA() {
        System.out.println("进入了A方法");
    }

    @Override
    protected void doB() {
        System.out.println("进入了B方法");
    }

    @Override
    public boolean isDoAnything() {
        return true;
    }

    public void doAllthings(){
        super.templeteMethod();
    }
}

Through the template method pattern, the algorithm that is considered as the invariant part can be encapsulated into the parent class for implementation, while the variable part can continue to be extended through inheritance. The behavior is controlled by the parent class and implemented by the subclass. Basic methods are implemented by subclasses, so subclasses can add corresponding functions through extensions, which conforms to the principle of opening and closing.

Guess you like

Origin blog.csdn.net/weixin_43195884/article/details/127759687