[design pattern learning] summary of several common design patterns

1, Introduction

Software Design Pattern, also known as design pattern, is a summary of code design experience that is repeatedly used, known by most people, classified and catalogued. It describes some recurring problems in the process of software design and the solutions to the problems. In other words, it is a series of routines to solve specific problems and a summary of the code design experience of predecessors. It is universal and can be used repeatedly. Its purpose is to improve the reusability, readability and reliability of the code.

Reference learning: Design pattern learning website

2, Several common design patterns

1. Singleton mode

Description: the relationship among classes, objects and instances. There are instances of Java objects in the heap area of the JVM. The traditional creation object (new className()) will create an instance, but only one specific instance is required in a specific scene, instead of creating multiple instances (different instances can have the same construction parameters, but the essence is different), If the task manager is opened, in order to avoid the waste of resources, you only need to create an instance.

Application scenario:

1. Count the number of people currently online (website counter): use a global object to record.
2. Printer (Device Manager): when there are two printers, only one printer outputs the same file.
3. Database connection pool (control resources): the single instance mode is generally adopted, because database connection is a kind of connection to database resources, which is not easy to create and destroy frequently. The use of database connection pool in database software system is mainly to save the efficiency loss caused by opening or closing database connection. This efficiency loss is still very expensive. Therefore, using singleton mode for maintenance can greatly reduce this loss.
4. Application log (resource sharing): generally, the log content is a sharing operation, and the content needs to be written continuously later, so it is usually designed as a single example.

Implementation method: hungry and lazy. The implementation code is as follows

/**
 * @AUTHOR LYF
 * @DATE 2021/5/1
 * @VERSION 1.0
 * @DESC
 *
 * 1.About the life cycle of static
 * Conclusion: it is not feasible to use static to save a variable so that the last value can be used next time the program runs.
 * Because although the life cycle of static variables is long (that is, the life cycle of classes), when the program is executed, that is, the
 * If all objects of the class have been recycled, or the ClassLoader that loads the class has been recycled, the class will be unloaded from the method area of the jvm, that is, the life cycle will end
 * https://www.cnblogs.com/hf-cherish/p/4970267.html
 */

class LazySingleton{
    private volatile static LazySingleton lazySingleton =null;//Runtime load
    private LazySingleton(){
    }

    public static synchronized LazySingleton getInstance(){
        if(lazySingleton==null){
            System.out.println("Not constructed..");
            lazySingleton = new LazySingleton();
        }else{
            System.out.println("Constructed..");
        }
        return lazySingleton;
    }

    public void method(){
        System.out.println("call method..");
    }
}

class HungrySingleton{
    private final static HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton(){

    }

    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }

    public void method(){
        System.out.println("call method....");
    }

}

public class SingletonModel {

    public static void main(String[]args){
        // First construction
        LazySingleton lazySingleton = LazySingleton.getInstance();// Calendar uses this mode
        lazySingleton.method();
        // Second construction, life cycle of static??
        LazySingleton lazySingleton2 = LazySingleton.getInstance();
        lazySingleton2.method();



        // Hungry man single case mode
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        hungrySingleton.method();

        if(lazySingleton==lazySingleton2){
            System.out.println("identical");
        }else {
            System.out.println("Different");

        }

//        for(int i =0;i<200;i++){
//            LazySingleton.getInstance().method();
//            try {
//                Thread.sleep(2000);
//            }catch (Exception e){
//                e.printStackTrace();
//            }
//        }

    }
}

Simple application

/**
 * @AUTHOR LYF
 * @DATE 2021/5/1
 * @VERSION 1.0
 * @DESC
 * application
 */
class Win extends JPanel{
      private static Win instance = new Win();

      private Win(){
          JLabel l1 = new JLabel(new ImageIcon("E:\\IdeaProjects\\java-base\\src\\main\\resources\\test.png"));
          this.add(l1);
      }

      public static Win getInstance(){
          return instance;
      }
}

class WinPanel extends JPanel{
    public WinPanel(){
        JLabel l1 = new JLabel(new ImageIcon("E:\\IdeaProjects\\java-base\\src\\main\\resources\\test.png"));
        this.add(l1);
    }
}

public class SingletonApplication {

    public static void main(String[]args){
         // frame
         JFrame jf = new JFrame("Hungry man single case mode");
         // Set layout
         jf.setLayout(new GridLayout(1,2));

         // container
         Container containerPane = jf.getContentPane();

         // Settings panel
         Win win1 = Win.getInstance();
         Win win2 = Win.getInstance();

         // Different examples
         WinPanel panel1 = new WinPanel();
         WinPanel panel2 = new WinPanel();

         containerPane.add(panel1);
         containerPane.add(panel2);

  //---------------------------------------

         containerPane.add(win1);
         containerPane.add(win2);

         if(win1==win2){
             System.out.println("It's the same");
         }else {
             System.out.println("Not the same");
         }

         jf.pack();
         jf.setLocation(500,300);
         jf.setVisible(true);
         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

}

2. Prototype design mode

Description: in order to reduce the overhead of construction, clone and copy existing objects directly to generate new instances. Applicable to those with too many construction parameters.
Application scenario:
Class initialization consumes more resources
An object generated by new requires a very cumbersome process (data preparation, access rights, etc.)
Constructors are complex
When a large number of objects are produced in the loop body
reference resources: Knowledge about cloning

/**
 * @AUTHOR LYF
 * @DATE 2021/5/1
 * @VERSION 1.0
 * @DESC
 * Prototype mode, clone, copy
 */
class ProtoModel implements Cloneable{
    public ProtoModel(){
        System.out.println("structure ProtoModel");
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("copy ProtoModel");
        return (ProtoModel)super.clone();
    }
}

public class ProtoTypeModel {


    public static void main(String[]args) throws CloneNotSupportedException {
        ProtoModel protoModel1= new ProtoModel();
        ProtoModel protoModel2=(ProtoModel)protoModel1.clone();
        if(protoModel1==protoModel2){
            System.out.println("identical");
        }else {
            System.out.println("Different");
        }

    }


}

3. Observer mode

Description: there is a one to many dependency between multiple objects. When the state of an object changes, all objects that depend on it are notified and automatically updated. This mode is sometimes called publish subscribe mode and model view mode. It is an object behavior mode.

Application: it is mostly used to realize the subscription function, such as the subscription of microblog. When we subscribe to someone's microblog account, when the person publishes a new message, we will be notified.

/**
 * @AUTHOR LYF
 * @DATE 2021/5/2
 * @VERSION 1.0
 * @DESC
 */

abstract class Subject{
    //private
    protected List<Observer> observerList = new ArrayList<>();
    protected List<String> msgList =new ArrayList<>();
    void addObserver(Observer observer){
        observerList.add(observer);
    }
    void remove(Observer observer){
        observerList.remove(observer);
    }

    void publicMsg(String msg)
    {
        msgList.add(new Date()+":"+msg);
    }

    abstract void notifyObserver();
}

class concreteSubject extends Subject{

    @Override
    void notifyObserver() {
        System.out.println("New message received,Notify all observers(subscriber)");
        for(Observer observer:observerList){
            observer.response(msgList.get(msgList.size()-1));
        }
    }
}


// Why interfaces rather than abstract classes?, It is to meet the rule, not to expand or realize the part
interface  Observer{
    void response(String receiveMsg);
}

class Observer1 implements Observer{

    @Override
    public void response(String receiveMsg) {
        System.out.println("Observer1 Observed target change,Receive the message--"+receiveMsg);
    }
}

class Observer2 implements Observer{

    @Override
    public void response(String receiveMsg) {
        System.out.println("Observer2 Observed target change,Receive the message--"+receiveMsg);
    }
}
public class ObserverModel {
    public static void main(String[]args){
        Subject subject = new concreteSubject();
        Observer observer1 = new Observer1();
        Observer observer2 = new Observer2();
        subject.addObserver(observer1);
        subject.addObserver(observer2);
        // Notification is triggered when a message is published
        subject.publicMsg("hello,this is a test!!");
        subject.notifyObserver();
        subject.remove(observer1);
        subject.publicMsg("hello,the notice ! observer1 has been removed!");
        subject.notifyObserver();


    }
}

4. Agency mode

Description: for some reason, it is necessary to provide a proxy for an object to control access to the object. At this time, the access object is not suitable or cannot directly reference the target object. The proxy object acts as the intermediary between the access object and the target object.

Application scenario: some non functional requirements in the business system, such as monitoring, statistics, authentication, transaction, log, etc. We decouple these additional functions from business functions and put them into the agent class for unified processing. In this way, we can decouple them from business and clearly divide responsibilities.
The remote object to be accessed is relatively large (such as video or large image), and its download takes a lot of time. In addition, for security reasons, it is necessary to shield the client from directly accessing real objects, such as the internal database of a unit.

// Abstract theme
interface Subject{
    void request();
}

class RealSubject implements Subject{
    //private String name;

    @Override
    public void request() {
        System.out.println("Real implementation theme....");
    }

}

class SubjectProxy{
    private Subject subject = null;

    public SubjectProxy(){
        if(subject==null){
            subject = new RealSubject();//Generate proxy services
        }
    }

    public void request(){
        System.out.println("Entry request");
        preRequest();
        subject.request();
        afterRequest();
    }

    private void preRequest(){
        System.out.println("Pair subject Pretreatment of");
    }
    private void afterRequest(){
        System.out.println("Pair subject Post treatment");
    }
}

public class ProxyTest {
    public static void main(String[]args){
        SubjectProxy subjectProxy = new SubjectProxy();
        subjectProxy.request();;
    }

}

Keywords: Java

Added by bhogg on Fri, 18 Feb 2022 18:12:59 +0200