Design pattern interview questions (summarize the most comprehensive interview questions!!!)

What is a design pattern

  • Design pattern is a set of code design experience that is repeatedly used, known by most people, and cataloged. The purpose of using design patterns is to reuse code, make it easier for others to understand, ensure code reliability and program reusability.

Why learn design patterns

  • Understand the source code: if you don't understand design patterns, look at the source code of Jdk, Spring, SpringMVC, IO, etc., you will be very confused, and you will be unable to do anything
  • Look at the code of the elder: is it all new projects that you take over when you go to a company? It is likely to be connected. Don't you need design patterns for the development of predecessors?
  • Write my ideal good code: I personally am like this anyway. I will be very serious about the project I develop. I treat him better than my girlfriend, and treat the project as my son

Design pattern classification

 

  • There are five kinds of creation mode: factory method mode, abstract factory mode, singleton mode, builder mode and prototype mode.

  • There are seven structural modes: adapter mode, decorator mode, agent mode, appearance mode, bridge mode, combination mode and sharing mode.

  • There are eleven behavioral modes: strategy mode, template method mode, observer mode, iteration sub mode, responsibility chain mode, command mode, memo mode, state mode, visitor mode, mediator mode, interpreter mode.

Six principles of design pattern

 

Open Close Principle

  • Principle: try to solve the demand change by extending the software entity, rather than modifying the existing code to complete the change
  • Description: a software product will change in its life cycle. Since change is an established fact, we should try to adapt to these changes in the design to improve the stability and flexibility of the project.
  • Advantages: the single principle tells us that each class has its own responsibility, and the Richter substitution principle cannot destroy the system of inheritance relations.

Liskov Substitution Principle

  • Principle: the base class used can use inherited subclasses anywhere to perfectly replace the base class.
  • The general meaning is: subclasses can extend the functions of the parent class, but cannot change the original functions of the parent class. Subclasses can implement the abstract methods of the parent class, but cannot override the non abstract methods of the parent class. Subclasses can add their own unique methods.
  • Advantages: increase the robustness of the program. Even if subclasses are added, the original subclasses can continue to run without affecting each other.

Dependency Inversion Principle

  • The core idea of dependency inversion principle is interface oriented programming

  • The dependency inversion principle requires us to refer to high-level abstract classes as much as possible when passing parameters in program code or in association relations,

  • This is the basis of the open and closed principle. The specific content is: interface programming depends on abstraction rather than concrete.

Interface aggregation principle

  • This principle means that using multiple isolated interfaces is better than using a single interface. It also means reducing the coupling degree between classes. From here, we can see that in fact, the design pattern is a software design idea, starting from the large-scale software architecture, for the convenience of upgrading and maintenance. So many times in the above: reduce dependency and coupling.
  • For example, the interfaces of payment class and order class need to be changed into two separate interfaces

Demeter Principle

  • Principle: an object should know as little as possible about other objects, which is referred to as inter class decoupling
  • The general meaning is that a class should try to reduce its dependence on other objects. The principle is low coupling and high cohesion. Only by making the coupling between modules as low as possible, can the reuse rate of code be improved.
  • Advantages: low coupling, high cohesion.

Principle of single responsibility

  • Principle thought: one method is only responsible for one thing.
  • Description: the principle of single responsibility is very simple. One method and one class are only responsible for one responsibility. The program changes of each responsibility will not affect other programs. This is common sense, and almost all programmers will follow this principle.
  • Advantages: reduce the coupling between classes, improve readability, increase maintainability and extensibility, and reduce the risk of variability.

Singleton mode

1. What is a singleton

  • Ensure that there is only one instance of a class, and provide an access point to access the global access point

2. Where is the singleton mode used

  1. The counter of the website is generally implemented in the singleton mode, otherwise it is difficult to synchronize.
  2. The log application of the application is generally implemented in the single instance mode. Only one instance can be operated, otherwise the content is not good to be added.
  3. The design of multithreaded thread pool generally adopts the singleton mode, because the thread pool should facilitate the control of threads in the pool
  4. Windows (Task Manager) is a typical singleton mode. It cannot open two
  5. windows (Recycle Bin) is also a typical singleton application. During the operation of the whole system, only one instance is maintained in the recycle bin.

3. Advantages and disadvantages of single case

advantage:

  1. In singleton mode, there is only one instance of an active singleton, and all instantiations of a singleton class result in the same instance. This prevents other objects from instantiating themselves and ensures that all objects access an instance
  2. Singleton mode has certain scalability. Classes control the instantiation process by themselves, and classes have corresponding scalability in changing the instantiation process.
  3. Provides controlled access to unique instances.
  4. Because there is only one object in the system memory, it can save system resources. When objects need to be created and destroyed frequently, the singleton mode can undoubtedly improve the performance of the system.
  5. Allow variable instances.
  6. Avoid multiple occupation of shared resources.

Disadvantages:

  1. It is not applicable to changing objects. If objects of the same type always change in different use case scenarios, a singleton will cause data errors and cannot save each other's states.
  2. Because there is no abstraction layer in the simple interest mode, it is very difficult to extend the singleton class.
  3. The responsibility of single instance class is too heavy, which violates the "single responsibility principle" to a certain extent.
  4. Misuse of singleton will bring some negative problems. For example, in order to save resources, designing database connection pool objects as singleton classes may lead to too many programs sharing connection pool objects and connection pool overflow; If the instantiated object is not used for a long time, the system will consider it as garbage and be recycled, which will lead to the loss of object state.

4. Precautions for using singleton mode:

  1. You cannot use reflection mode to create a singleton, otherwise a new object will be instantiated
  2. Pay attention to thread safety when using lazy singleton mode
  3. Hungry singleton pattern and lazy singleton pattern construction methods are private, so they cannot be inherited. Some singleton patterns can be inherited (such as registered pattern)

5. Single instance anti reflection vulnerability attack

private static boolean flag = false;

private Singleton() {

	if (flag == false) {
		flag = !flag;
	} else {
		throw new RuntimeException("Singleton mode is violated!");
	}
}

public static void main(String[] args) {

}

6. How to select a singleton creation method

  • If you don't need to delay loading singletons, you can use enumeration or hungry Chinese style, which is relatively better than hungry Chinese style. If you need to delay loading, you can use static inner classes or lazy style. Relatively speaking, static inner classes are better than lazy Korean style. It's better to use hungry Han style

7. Single instance creation method

(mainly lazy and lazy)

  1. Hungry Chinese style: when the class is initialized, the object will be loaded immediately. The thread is inherently safe and the calling efficiency is high.
  2. Lazy: the object will not be initialized during class initialization, but will be created when it really needs to be used, with lazy loading function.
  3. Static internal mode: it combines the respective advantages of lazy and hungry, and loads objects only when they are really needed. Loading classes is thread safe.
  4. Enumeration singleton: the advantages of using enumeration to implement singleton mode: simple implementation and high call efficiency. Enumeration itself is a singleton, which is fundamentally guaranteed by the jvm! Avoid vulnerabilities through reflection and deserialization. The disadvantage is that there is no delay in loading.
  5. Double detection lock mode (it may be initialized many times due to the reordering of JVM essence, which is not recommended)

1. Hungry Han style

  1. Hungry Chinese style: when the class is initialized, the object will be loaded immediately. The thread is inherently safe and the calling efficiency is high.
package com.lijie;

//Hungry Han style
public class Demo1 {

    // When the class is initialized, the object will be loaded immediately, which is thread safe and efficient
    private static Demo1 demo1 = new Demo1();

    private Demo1() {
        System.out.println("private Demo1 Initialization of construction parameters");
    }

    public static Demo1 getInstance() {
        return demo1;
    }

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


2. Lazy style

  1. Lazy: the object will not be initialized during class initialization, but will be created when it really needs to be used, with lazy loading function.
package com.lijie;

//Lazy style
public class Demo2 {

    //When class is initialized, the object will not be initialized, but will be created when it really needs to be used.
    private static Demo2 demo2;

    private Demo2() {
        System.out.println("private Demo2 Initialization of construction parameters");
    }

    public synchronized static Demo2 getInstance() {
        if (demo2 == null) {
            demo2 = new Demo2();
        }
        return demo2;
    }

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


3. Static internal class

  1. Static internal mode: it combines the respective advantages of lazy and hungry, and loads objects only when they are really needed. Loading classes is thread safe.
package com.lijie;

// Static inner class mode
public class Demo3 {

    private Demo3() {
        System.out.println("private Demo3 Initialization of construction parameters");
    }

    public static class SingletonClassInstance {
        private static final Demo3 DEMO_3 = new Demo3();
    }

    // Method is not synchronized
    public static Demo3 getInstance() {
        return SingletonClassInstance.DEMO_3;
    }

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

4. Enumeration singleton

  1. Enumeration singleton: the advantages of using enumeration to implement singleton mode: simple implementation and high call efficiency. Enumeration itself is a singleton, which is fundamentally guaranteed by the jvm! Avoid vulnerabilities through reflection and deserialization. The disadvantage is that there is no delay in loading.
package com.lijie;

//Advantages of using enumeration to implement singleton mode: simple implementation, enumeration itself is a singleton, which is fundamentally guaranteed by the jvm! Avoid the vulnerability of reflection and deserialization. There is no delay in loading
public class Demo4 {

    public static Demo4 getInstance() {
        return Demo.INSTANCE.getInstance();
    }

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

    //Define enumeration
	private static enum Demo {
		INSTANCE;
		// Enumeration element is a singleton
		private Demo4 demo4;

		private Demo() {
			System.out.println("enumeration Demo Private construction parameters");
			demo4 = new Demo4();
		}

		public Demo4 getInstance() {
			return demo4;
		}
	}
}


5. Double detection lock mode

  1. Double detection lock mode (it may be initialized many times due to the reordering of JVM essence, which is not recommended)
package com.lijie;

//Double detection lock mode
public class Demo5 {

	private static Demo5 demo5;

	private Demo5() {
		System.out.println("private Demo4 Initialization of construction parameters");
	}

	public static Demo5 getInstance() {
		if (demo5 == null) {
			synchronized (Demo5.class) {
				if (demo5 == null) {
					demo5 = new Demo5();
				}
			}
		}
		return demo5;
	}

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

Factory mode

1. What is factory mode

  • It provides the best way to create objects. In factory mode, we do not expose the creation logic to the client when creating objects, and we use a common interface to point to the newly created objects. It realizes the separation of creator and caller. The factory mode is divided into simple factory, factory method and abstract factory mode

2. Benefits of factory mode

  • Factory mode is the most commonly used instantiation object mode. It is a mode that uses factory method to replace new operation.
  • Using the factory mode can reduce the coupling of the program and provide great convenience for later maintenance and modification.
  • Implementation classes will be selected and objects created for unified management and control. This decouples the caller from our implementation class.

3. Why should we learn factory design mode

  • I don't know if you asked about the source code in your interview questions. Do you know the source code of Spring, MyBatis, etc. if you want to learn the source code of many frameworks, or you want to develop your own framework, you must first master the design pattern (factory design pattern is used very widely)

4. Factory design pattern in spring development

1.Spring IOC

  • You can see from the Spring source code that the factory design pattern is used in the process of creating bean s in the Spring IOC container

  • In Spring, whether bean s are created through xml configuration, configuration classes or annotations, most of them are created through simple factories.

  • When the container gets the beanName and class types, it dynamically creates a specific object through reflection, and finally puts the created object into the Map.

2. Why does Spring IOC use factory design pattern to create beans

  • In actual development, if our A object calls B, B calls C, and C calls D, the coupling of our program will become higher. (coupling can be roughly divided into dependencies between classes and dependencies between methods.)

  • In the three-tier architecture programming of a long time ago, when the control layer called the business layer, when the business layer called the data access layer, they were all direct new objects, which greatly improved the coupling, high code repetition, and objects flying all over the sky

  • In order to avoid this situation, Spring uses factory mode programming to write a factory and create beans by the factory. In the future, if we want objects, we can directly manage the factory. The rest is not our business. There is a static Map set in the factory of Spring IOC container, which is to make the factory conform to the singleton design mode, that is, each object is produced only once, and the object is stored in the Map set after it is produced, so as to ensure that the instance will not affect the program efficiency repeatedly.

5. Factory mode classification

  • Factory mode is divided into simple factory, factory method and abstract factory mode
Simple factory: used to produce any product in the same grade structure. (expansion and addition of products are not supported)
Factory method: used to produce fixed products in the same grade structure. (support the expansion and increase of products)   
Abstract factory: used to produce all products of different product families. (it does not support expanding and adding products; it supports adding product families)

Let me use the code to demonstrate:

5.1 simple factory mode

What is the simple factory model

  • The simple factory mode is equivalent to that there are various products in a factory. Created in a class, customers do not need to know the name of specific products, but only need to know the parameters corresponding to the product class. However, the responsibility of the factory is too heavy, and when there are too many types, it is not conducive to the expansion and maintenance of the system.

Code demonstration:

  1. Create factory
package com.lijie;

public interface Car {
	public void run();
}
  1. Create factory products (BMW)
package com.lijie;

public class Bmw implements Car {
	public void run() {
		System.out.println("I am a BMW...");
	}
}
  1. Create another product (Audi)
package com.lijie;

public class AoDi implements Car {
	public void run() {
		System.out.println("I'm Audi..");
	}
}
  1. Create a core factory class, and it is up to him to decide which product to call
package com.lijie;

public class CarFactory {

	 public static Car createCar(String name) {
		if ("".equals(name)) {
             return null;
		}
		if(name.equals("audi")){
			return new AoDi();
		}
		if(name.equals("bmw")){
			return new Bmw();
		}
		return null;
	}
}
  1. Demonstrate a specific example of creating a factory
package com.lijie;

public class Client01 {

	public static void main(String[] args) {
		Car aodi  =CarFactory.createCar("audi");
		Car bmw  =CarFactory.createCar("bmw");
		aodi.run();
		bmw.run();
	}
}

Advantages / disadvantages of single plant

  • Advantages: the simple factory pattern can decide which specific class object should be created according to the information given by the outside world. It clearly distinguishes their respective responsibilities and powers, which is conducive to the optimization of the entire software architecture.
  • Disadvantages: obviously, the factory class centralizes the creation logic of all instances, which is easy to violate GRASPR's highly cohesive responsibility allocation principle

5.2 factory method mode

What is factory method mode

  • Factory Method pattern, also known as polymorphic factory pattern. In the Factory Method mode, the core factory class is no longer responsible for the creation of all products, but delegates the specific creation work to subclasses. The core class becomes an abstract factory role, which is only responsible for giving the interface that the specific factory subclass must implement, without touching the details of which product class should be instantiated

Code demonstration:

  1. Create factory
package com.lijie;

public interface Car {
	public void run();
}
  1. Create a factory method call interface (all products need new and must inherit it to implement the method)
package com.lijie;

public interface CarFactory {

	Car createCar();

}
  1. Create factory products (Audi)
package com.lijie;

public class AoDi implements Car {
	public void run() {
		System.out.println("I'm Audi..");
	}
}
  1. Create another product in the factory (BMW)
package com.lijie;

public class Bmw implements Car {
	public void run() {
		System.out.println("I am a BMW...");
	}
}
  1. Create an instance of the factory method call interface (Audi)
package com.lijie;

public class AoDiFactory implements CarFactory {

	public Car createCar() {
	
		return new AoDi();
	}
}
  1. Create an instance of the factory method call interface (BMW)
package com.lijie;

public class BmwFactory implements CarFactory {

	public Car createCar() {

		return new Bmw();
	}

}
  1. Demonstrate a specific example of creating a factory
package com.lijie;

public class Client {

	public static void main(String[] args) {
		Car aodi = new AoDiFactory().createCar();
		Car jili = new BmwFactory().createCar();
		aodi.run();
		jili.run();
	}
}

5.3 abstract factory mode

What is the abstract factory pattern

  • An abstract factory is simply a factory of a factory. An abstract factory can create a specific factory and produce specific products by a specific factory.

    Code demonstration:
  1. Create the first sub factory and implementation class
package com.lijie;

//automobile
public interface Car {
	   void run();
}

 class CarA implements Car{

	public void run() {
		System.out.println("bmw");
	}
	
}
 class CarB implements Car{

	public void run() {
		System.out.println("Mobai");
	}
	
}
  1. Create the second sub factory and implementation class
package com.lijie;

//engine
public interface Engine {

    void run();

}

class EngineA implements Engine {

    public void run() {
        System.out.println("Turn fast!");
    }

}

class EngineB implements Engine {

    public void run() {
        System.out.println("Turn slowly!");
    }

}
  1. Create a general factory and implementation class (the implementation class of the General Factory determines the instance of that factory to call)
package com.lijie;

public interface TotalFactory {
	// Create a car
	Car createChair();
	// Create engine
	Engine createEngine();
}

//The total factory implementation class, which decides to call the instance of which factory
class TotalFactoryReally implements TotalFactory {

	public Engine createEngine() {

		return new EngineA();
	}

	public Car createChair() {

		return new CarA();
	}
}

  1. Run test
package com.lijie;

public class Test {

    public static void main(String[] args) {
        TotalFactory totalFactory2 = new TotalFactoryReally();
        Car car = totalFactory2.createChair();
        car.run();

        TotalFactory totalFactory = new TotalFactoryReally();
        Engine engine = totalFactory.createEngine();
        engine.run();
    }
}

proxy pattern

1. What is the agency mode

  • By controlling the access of an object through a proxy, you can handle / add new functions before and after the method is called by this object. (that is, the P-micro implementation of AO)

  • Without modifying the original code or even the original business process, the agent directly cuts in new code and adds new functions in the business process, which is also very similar to Spring's (aspect oriented programming)

2. Proxy mode application scenarios

  • Spring AOP, log printing, exception handling, transaction control, permission control, etc

3. Classification of agents

  • Static proxy (statically defined proxy class)
  • Dynamic proxy (dynamically generate proxy classes, also known as Jdk's own dynamic proxy)
  • Cglib, javaassist (bytecode operation Library)

4. Differences between the three agents

  1. Static agent: simple agent mode is the theoretical basis of dynamic agent. Commonly used in proxy mode
  2. jdk dynamic proxy: use reflection to complete the proxy. You need a top-level interface to use it. The common mapper file of mybatis is a proxy.
  3. cglib dynamic proxy: it also uses reflection to complete the proxy. It can directly proxy classes (jdk dynamic proxy cannot). It uses bytecode technology and cannot inherit final classes. (you need to import the jar package)

5. Demonstrate three agents with code

5.1. static proxy

What is a static proxy

  • The programmer creates or tools generate the source code of the proxy class, and then compiles the proxy class. The so-called static means that the bytecode file of the proxy class already exists before the program runs, and the relationship between the proxy class and the delegate class is determined before the program runs.

Code demonstration:

  • I have a piece of code like this: (how can I open and close transactions without modifying the UserDao interface class)
package com.lijie;

//Interface class
public class UserDao{
	public void save() {
		System.out.println("Save data method");
	}
}
package com.lijie;

//Run test class
public  class Test{
	public static void main(String[] args) {
		UserDao userDao = new UserDao();
		userDao.save();
	}
}

Modify code and add proxy class

package com.lijie;

//proxy class
public class UserDaoProxy extends UserDao {
	private UserDao userDao;

	public UserDaoProxy(UserDao userDao) {
		this.userDao = userDao;
	}

	public void save() {
		System.out.println("Open things...");
		userDao.save();
		System.out.println("Close things...");
	}

}
//Add the test class of static agent
public class Test{
	public static void main(String[] args) {
		UserDao userDao = new UserDao();
		UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
		userDaoProxy.save();
	}
}
  • Disadvantages: each object that needs proxy needs to write proxy repeatedly, which is very uncomfortable,
  • Advantages: but the proxy can be implemented in the way of actual object or interface

2.2 dynamic agent

What is dynamic proxy

  • Dynamic proxy is also called JDK proxy and interface proxy.

  • The object of dynamic proxy is to use the API of JDK to dynamically build proxy objects in memory (dynamically generate the class file of proxy class according to the interface of the proxy and load the running process), which is called dynamic proxy

package com.lijie;

//Interface
public interface UserDao {
    void save();
}
package com.lijie;

//Interface implementation class
public class UserDaoImpl implements UserDao {
	public void save() {
		System.out.println("Save data method");
	}
}
  • //The following is the proxy class, which can be reused. Unlike the static proxy, you need to write the proxy repeatedly
package com.lijie;

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

// Each time a dynamic proxy class object is generated, the invoking handler object of the InvocationHandler interface is implemented
public class InvocationHandlerImpl implements InvocationHandler {

	// This is actually a business implementation class object, which is used to call specific business methods
    private Object target;

    // Pass in the target object through the constructor
    public InvocationHandlerImpl(Object target) {
        this.target = target;
    }

    //Agent method of dynamic agent actual operation
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Call to start processing");
        //The following invoke() method creates objects in a reflective way. The first parameter is the object to be created, and the second parameter is the parameter that constitutes the method. The second parameter determines which construction method to use to create the object
		Object result = method.invoke(target, args);
        System.out.println("Call end processing");
        return result;
    }
}
  • //Using dynamic proxies using proxy methods
package com.lijie;

import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        // Proxied object
        UserDao userDaoImpl = new UserDaoImpl();
        InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDaoImpl);

        //Class loader
        ClassLoader loader = userDaoImpl.getClass().getClassLoader();
        Class<?>[] interfaces = userDaoImpl.getClass().getInterfaces();

        // Main loaders, a set of interfaces, and call processing dynamic proxy instances
        UserDao newProxyInstance = (UserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
        newProxyInstance.save();
    }
}
  • Disadvantages: it must be interface oriented, and the target business class must implement the interface
  • Advantages: you don't need to care about the proxy class. You only need to specify which object to proxy at the run time

5.3.CGLIB dynamic agent

CGLIB dynamic agent principle:

  • Using the asm open source package, load the class file of the proxy object class, and process it by modifying its bytecode to generate subclasses.

What is CGLIB dynamic proxy

  • CGLIB dynamic proxy is the same as jdk proxy, which uses reflection to complete the proxy. The difference is that it can directly proxy classes (jdk dynamic proxy cannot, it must implement the interface of the target business class). The underlying layer of CGLIB dynamic proxy uses bytecode technology, and CGLIB dynamic proxy cannot inherit the final class. (CGLIB dynamic agent needs to import jar package)

Code demonstration:

package com.lijie;

//Interface
public interface UserDao {
    void save();
}
package com.lijie;

//Interface implementation class
public class UserDaoImpl implements UserDao {
	public void save() {
		System.out.println("Save data method");
	}
}
package com.lijie;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

//Agent main category
public class CglibProxy implements MethodInterceptor {
	private Object targetObject;
	// If the target type here is Object, you can accept any parameter as the proxied class to realize dynamic proxy
	public Object getInstance(Object target) {
		// Set the classes that need to create subclasses
		this.targetObject = target;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(target.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}

	//Agent practical method
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("Open things");
		Object result = proxy.invoke(targetObject, args);
		System.out.println("Close things");
		// Return proxy object
		return result;
	}
}

package com.lijie;

//Test CGLIB dynamic agent
public class Test {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl());
        userDao.save();
    }
}

Builder pattern

1. What is the builder mode

  • Builder mode: it separates the construction of a complex object from its representation, so that the same construction process can be created in different ways.

  • The factory class pattern provides products that create a single class

  • The builder mode is to centralize all kinds of products for management and use them for products with different attributes

The builder mode usually includes the following roles:

  1. B uilder: provide an abstract interface to standardize the construction of various components of product objects. This interface specifies which parts of complex objects should be created, and does not involve the creation of specific object components.
  2. ConcreteBuilder: it implements the Builder interface and concretes the creation of various parts of complex objects for different business logic. After the construction process is completed, provide examples of products.
  3. Director: call the specific builder to create each part of the complex object. The director does not involve the information of the specific product, but is only responsible for ensuring that each part of the object is created completely or in a certain order.
  4. Product: complex object to create.

2. Usage scenarios of builder mode

Usage scenario:

  1. The objects that need to be generated have complex internal structures.
  2. The internal attributes of the object to be generated are interdependent.
  • The difference from the factory mode is that the builder mode pays more attention to the assembly sequence of parts.

  • StringBuilder in JAVA is created by the builder pattern. It combines a single character char array

  • Spring is not a builder mode. The operations it provides should be some operations on the string itself, rather than creating or changing a string.

3. Code cases

  1. Create an equipment object Arms
package com.lijie;

//Equipment
public class Arms {
	//Helmet
	private String helmet;
	//Armor
	private String armor;
	//arms
	private String weapon;
	
	//Omit Git and Set methods
}
  1. Create a Builder interface (give an abstract interface to standardize the construction of each component of the product object. This interface is only a specification)
package com.lijie;

public interface PersonBuilder {

	void builderHelmetMurder();

	void builderArmorMurder();

	void builderWeaponMurder();

	void builderHelmetYanLong();

	void builderArmorYanLong();

	void builderWeaponYanLong();

	Arms BuilderArms(); //assemble
}

  1. Create a Builder implementation class (this class mainly implements which parts of complex object creation need what attributes)
package com.lijie;

public class ArmsBuilder implements PersonBuilder {
    private Arms arms;

    //Create an Arms instance to call the set method
    public ArmsBuilder() {
        arms = new Arms();
    }

    public void builderHelmetMurder() {
        arms.setHelmet("Lethal helmet");
    }

    public void builderArmorMurder() {
        arms.setArmor("Deadly armor");
    }

    public void builderWeaponMurder() {
        arms.setWeapon("Lethal Sabre");
    }

    public void builderHelmetYanLong() {
        arms.setHelmet("Yanlong helmet");
    }

    public void builderArmorYanLong() {
        arms.setArmor("Dragon Armor");
    }

    public void builderWeaponYanLong() {
        arms.setWeapon("Yanlong sword");
    }

    public Arms BuilderArms() {
        return arms;
    }
}

  1. Director (call the specific builder to create each part of the complex object. The director does not involve the information of the specific product, but is only responsible for ensuring that each part of the object is created completely or in a certain order)
package com.lijie;

public class PersonDirector {
	
	//assemble
	public Arms constructPerson(PersonBuilder pb) {
		pb.builderHelmetYanLong();
		pb.builderArmorMurder();
		pb.builderWeaponMurder();
		return pb.BuilderArms();
	}

	//Test here
	public static void main(String[] args) {
		PersonDirector pb = new PersonDirector();
		Arms arms = pb.constructPerson(new ArmsBuilder());
		System.out.println(arms.getHelmet());
		System.out.println(arms.getArmor());
		System.out.println(arms.getWeapon());
	}
}

Template method mode

1. What is template method

  • Template method pattern: define the algorithm skeleton (parent class) in an operation, and delay some steps to the child class. Template method allows subclasses to redefine the structure of an algorithm without changing its structure

2. When to use the template method

  • When implementing some operations, the overall steps are very fixed, but. When a small part needs to be changed, you can use the template method pattern to abstract the easily changed part for subclass implementation.

3. Where is the template method used in the application scenario in the actual development

  • In fact, template method patterns are used in many frameworks
  • For example: encapsulation of database access, Junit unit test, call of doGet/doPost method in servlet, etc

4. Template method in real life

For example:

  1. When we go to the restaurant for dinner, the restaurant provides us with a template: look at the menu, order, eat, pay, and leave. (here, "order and pay" is uncertain, and it is completed by subclasses, while others are a template.)

5. Code implementation template method mode

  1. Define a template first. Let subclasses implement the ordering and payment in the template.
package com.lijie;

//Template method
public abstract class RestaurantTemplate {

	// 1. Look at the menu
	public void menu() {
		System.out.println("Look at the menu");
	}

	// 2. Order business
	abstract void spotMenu();

	// 3. Dining business
	public void havingDinner(){ System.out.println("having dinner"); }

	// 3. Payment business
	abstract void payment();

	// 3. Leave
	public void GoR() { System.out.println("leave"); }

	//General structure of formwork
	public void process(){
		menu();
		spotMenu();
		havingDinner();
		payment();
		GoR();
	}
}

  1. Specific template method subclass 1
package com.lijie;

public class RestaurantGinsengImpl extends RestaurantTemplate {

    void spotMenu() {
        System.out.println("Ginseng");
    }

    void payment() {
        System.out.println("5 fast");
    }
}
  1. Specific template method subclass 2
package com.lijie;

public class RestaurantLobsterImpl  extends RestaurantTemplate  {

    void spotMenu() {
        System.out.println("lobster");
    }

    void payment() {
        System.out.println("50 block");
    }
}
  1. Client test
package com.lijie;

public class Client {

    public static void main(String[] args) {
        //Call the first template instance
        RestaurantTemplate restaurantTemplate = new RestaurantGinsengImpl();
        restaurantTemplate.process();
    }
}

Appearance mode

1. What is appearance mode

  • Appearance mode: also known as facade mode, it hides the complexity of the system and provides an interface for the client to access the system.

  • It adds an interface to the existing system, and uses this interface to hide the complexity of the actual system.

  • Using the appearance mode, it looks like an interface externally, but in fact, many complex interfaces have been implemented internally

2. Appearance mode example

  • After registering, users need to call Alibaba SMS interface, email interface and wechat push interface.
  1. Create Alibaba SMS interface
package com.lijie;

//Alibaba SMS message
public interface AliSmsService {
	void sendSms();
}
package com.lijie;

public class AliSmsServiceImpl implements AliSmsService {

    public void sendSms() {
        System.out.println("Alibaba SMS message");
    }

}
  1. Create mail interface
package com.lijie;

//send mail message
public interface EamilSmsService {
	void sendSms();
}
package com.lijie;

public class EamilSmsServiceImpl implements   EamilSmsService{
	public void sendSms() {
		System.out.println("send mail message");
	}
}
  1. Create wechat push interface
package com.lijie;

//Wechat message push
public interface WeiXinSmsService {
   void sendSms();
}
package com.lijie;

public class WeiXinSmsServiceImpl implements  WeiXinSmsService {
    public void sendSms() {
        System.out.println("Send wechat message push");
    }
}
  1. Create a facade (the facade looks very simple to use, complex things and encapsulated by the facade)
package com.lijie;

public class Computer {
	AliSmsService aliSmsService;
	EamilSmsService eamilSmsService;
	WeiXinSmsService weiXinSmsService;

	public Computer() {
		aliSmsService = new AliSmsServiceImpl();
		eamilSmsService = new EamilSmsServiceImpl();
		weiXinSmsService = new WeiXinSmsServiceImpl();
	}

	//Just call it
	public void sendMsg() {
		aliSmsService.sendSms();
		eamilSmsService.sendSms();
		weiXinSmsService.sendSms();
	}
}
  1. Start test
package com.lijie;

public class Client {

    public static void main(String[] args) {
        //Normal mode requires this
        AliSmsService aliSmsService = new AliSmsServiceImpl();
        EamilSmsService eamilSmsService = new EamilSmsServiceImpl();
        WeiXinSmsService weiXinSmsService = new WeiXinSmsServiceImpl();
        aliSmsService.sendSms();
        eamilSmsService.sendSms();
        weiXinSmsService.sendSms();

        //Simplify the method with appearance mode
        new Computer().sendMsg();
    }
}

Prototype mode

1. What is the prototype mode

  • Prototype design pattern is simply cloning

  • The prototype shows that there is an example of a template, which can be customized. Prototype mode is often used to create complex or time-consuming instances, because in this case, copying an existing instance can make the program run more efficiently.

2. Application scenarios of prototype mode

  1. Class initialization needs to digest a lot of resources, including data, hardware resources, etc. At this time, we can avoid these consumption by copying the prototype.
  2. When an object generated through new requires very cumbersome data preparation or permissions, you can use the prototype pattern.
  3. When an object needs to be accessed by other objects, and each caller may need to modify its value, you can consider using the prototype mode to copy multiple objects for the caller to use, that is, protective copy.

Many cases in our Spring framework use prototypes.

3. Usage of prototype mode

  1. Implement clonable interface. There is a clonable interface in the java language, which has only one function, that is, to inform the virtual machine at runtime that it can safely use the clone method on the class that implements this interface. In java virtual machine, only the classes that implement this interface can be copied, otherwise CloneNotSupportedException will be thrown at runtime.

  2. Override the clone method in the Object class. In Java, the parent class of all classes is the Object class. There is a clone method in the Object class, which is used to return a copy of the Object, but its scope is of protected type, and general classes cannot be called. Therefore, the Prototype class needs to modify the scope of the clone method to public type.

3.1 prototype mode is divided into shallow replication and deep replication

  1. (shallow copy) only copies the basic type data, while the reference type data only copies a reference address.

  2. (deep copy) a new memory address is opened in the computer to store the copied objects.

4. Code demonstration

  1. Create User class
package com.lijie;

import java.util.ArrayList;

public class User implements Cloneable {
    private String name;
    private String password;
    private ArrayList<String> phones;

    protected User clone() {
        try {
            User user = (User) super.clone();
            //Key point: if you want to copy together with the reference type, you need to add the following code. If you don't add it, you will copy the reference address
            user.phones = (ArrayList<String>) this.phones.clone();//Set up deep copy
            return user;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
	
	//Omit all attribute Git Set methods
}
  1. Test replication
package com.lijie;

import java.util.ArrayList;

public class Client {
    public static void main(String[] args) {
        //Create User prototype object
        User user = new User();
        user.setName("Li San");
        user.setPassword("123456");
        ArrayList<String> phones = new ArrayList<>();
        phones.add("17674553302");
        user.setPhones(phones);

        //copy a user object, and the properties of the object
        User user2 = user.clone();
        user2.setPassword("654321");

        //Check whether the two objects are one
        System.out.println(user == user2);

        //View attribute content
        System.out.println(user.getName() + " | " + user2.getName());
        System.out.println(user.getPassword() + " | " + user2.getPassword());
        //View copy for reference type
        System.out.println(user.getPhones() == user2.getPhones());
    }
}
  1. If you do not need deep copy, you need to delete the
//The default reference type is shallow copy, which is set to deep copy
user.phones = (ArrayList<String>) this.phones.clone();

Strategy mode

1. What is the strategic mode

  • It defines a series of algorithms or logic or operations in the same sense, and encapsulates each algorithm, logic and operation, so that they can also be replaced with each other. (actually, the policy pattern is widely used in Java.)

  • I think it's mainly to simplify the complexity and difficulty of maintaining if...else.

2. Application scenario of strategy mode

  • The purpose of policy pattern is to encapsulate each algorithm or logic into an independent class with a common interface for a group of algorithms or logic, so that they can be replaced with each other.
  1. For example: I want to make three strategies with different discount intensity for different members, junior member, intermediate member and senior member (three different calculations).

  2. For example, I want a payment module, including wechat payment, Alipay payment, UnionPay payment, etc

3. Advantages and disadvantages of strategic mode

  • Advantages: 1. The algorithm can be switched freely. 2. Avoid using multiple conditional judgments. 3. The scalability is very good.

  • Disadvantages: 1. The number of policy classes will increase. 2. All policy classes need to be exposed.

4. Code demonstration

  • The analog payment module includes wechat payment, Alipay payment and UnionPay payment
  1. Define abstract public methods
package com.lijie;

//Policy pattern defines abstract methods. All support public interfaces
abstract class PayStrategy {

	// Payment logic method
	abstract void algorithmInterface();

}
  1. Define and realize wechat payment
package com.lijie;

class PayStrategyA extends PayStrategy {

	void algorithmInterface() {
		System.out.println("Wechat payment");
	}
}
  1. Define and realize Alipay payment
package com.lijie;

class PayStrategyB extends PayStrategy {

	void algorithmInterface() {
		System.out.println("Alipay payment");
	}
}
  1. Define and realize UnionPay payment
package com.lijie;

class PayStrategyC extends PayStrategy {

	void algorithmInterface() {
		System.out.println("UnionPay payment");
	}
}
  1. Define the following maintenance algorithm strategy
package com.lijie;// Use context to maintain algorithm policy

class Context {

	PayStrategy strategy;

	public Context(PayStrategy strategy) {
		this.strategy = strategy;
	}

	public void algorithmInterface() {
		strategy.algorithmInterface();
	}

}
  1. Run test
package com.lijie;

class ClientTestStrategy {
	public static void main(String[] args) {
		Context context;
		//Use payment logic A
		context = new Context(new PayStrategyA());
		context.algorithmInterface();
		//Use payment logic B
		context = new Context(new PayStrategyB());
		context.algorithmInterface();
		//Use payment logic C
		context = new Context(new PayStrategyC());
		context.algorithmInterface();
	}
}

Observer mode

1. What is observer mode

  • First, let's talk about what is behavioral model. Behavioral model focuses on the interaction between objects in the system, solves the mutual communication and cooperation between objects in the system at runtime, and further clarifies the responsibilities of objects.

  • Observer mode is a behavioral model, also known as publish subscribe mode. It defines a one to many dependency between objects, so that when an object changes state, all objects that depend on it will be notified and automatically updated.

2. Responsibilities of the model

  • Observer mode is mainly used for 1-to-N notification. When the state of an object changes, he needs to inform a series of objects in time to make them make corresponding decisions.

There are two ways to implement:

  1. Push: each time, the notification will be sent to all observers by broadcasting, and all observers can only passively receive it.
  2. La: as long as the observer knows the situation, he can decide when to get the content and what content to get.

3. Observer mode application scenario

  1. For related behavior scenarios, it should be noted that related behaviors are separable rather than "combined" relationships. Event multi-level trigger scenario.
  2. Cross system message exchange scenarios, such as message queues and event bus processing mechanisms.

4. Code implementation observer mode

  1. Define an abstract observer, and each implementation class that implements the interface is a concrete observer.
package com.lijie;

//The interface of the observer, which is used to store the common methods of the observer
public interface Observer {
    // Observer approach
    void update(int state);
}
  1. Define specific observers
package com.lijie;

// Specific observer
public class ObserverImpl implements Observer {

    // Attributes of specific observers
    private int myState;

    public void update(int state) {
        myState=state;
        System.out.println("Receive message,myState Change the value to:"+state);
    }

    public int getMyState() {
        return myState;
    }
}
  1. Define topics. The topic defines the observer array and implements the operations of adding, deleting and notifying.
package com.lijie;

import java.util.Vector;

//Define topics, define observer arrays, and implement add, delete, and notify operations.
public class Subjecct {
	//The storage set of observers, ArrayList is not recommended, and the thread is unsafe,
	private Vector<Observer> list = new Vector<>();

	// Register observer method
	public void registerObserver(Observer obs) {
		list.add(obs);
	}
    // Delete observer method
	public void removeObserver(Observer obs) {
		list.remove(obs);
	}

	// Notify all observers of updates
	public void notifyAllObserver(int state) {
		for (Observer observer : list) {
			observer.update(state);
		}
	}
}
  1. Define a specific one. It inherits the Subject class and implements specific businesses here. In a specific project, there will be many such classes.
package com.lijie;

//Specific topics
public class RealObserver extends Subjecct {
    //Properties of the observed object
	 private int state;
	 public int getState(){
		 return state;
	 }
	 public void  setState(int state){
		 this.state=state;
		 //Subject object (target object) value changes
		 this.notifyAllObserver(state);
	 }
}
  1. Run test
package com.lijie;

public class Client {

	public static void main(String[] args) {
		// Target object
		RealObserver subject = new RealObserver();
		// Create multiple observers
		ObserverImpl obs1 = new ObserverImpl();
		ObserverImpl obs2 = new ObserverImpl();
		ObserverImpl obs3 = new ObserverImpl();
		// Register to the observation queue
		subject.registerObserver(obs1);
		subject.registerObserver(obs2);
		subject.registerObserver(obs3);
		// Change State
		subject.setState(300);
		System.out.println("obs1 Observer's MyState The status value is:"+obs1.getMyState());
		System.out.println("obs2 Observer's MyState The status value is:"+obs2.getMyState());
		System.out.println("obs3 Observer's MyState The status value is:"+obs3.getMyState());
		// Change State
		subject.setState(400);
		System.out.println("obs1 Observer's MyState The status value is:"+obs1.getMyState());
		System.out.println("obs2 Observer's MyState The status value is:"+obs2.getMyState());
		System.out.println("obs3 Observer's MyState The status value is:"+obs3.getMyState());
	}
}

That's the end of the article. Yes, it's gone

Observer method public void removeobserver (observer OBS) {list.remove (OBS);}

// Notify all observers of updates
public void notifyAllObserver(int state) {
	for (Observer observer : list) {
		observer.update(state);
	}
}

}

4. Specifically, he inherits Subject Class, which implements specific businesses here. In specific projects, there will be many such classes.
```java
package com.lijie;

//Specific topics
public class RealObserver extends Subjecct {
    //Properties of the observed object
	 private int state;
	 public int getState(){
		 return state;
	 }
	 public void  setState(int state){
		 this.state=state;
		 //Subject object (target object) value changes
		 this.notifyAllObserver(state);
	 }
}
  1. Run test
package com.lijie;

public class Client {

	public static void main(String[] args) {
		// Target object
		RealObserver subject = new RealObserver();
		// Create multiple observers
		ObserverImpl obs1 = new ObserverImpl();
		ObserverImpl obs2 = new ObserverImpl();
		ObserverImpl obs3 = new ObserverImpl();
		// Register to the observation queue
		subject.registerObserver(obs1);
		subject.registerObserver(obs2);
		subject.registerObserver(obs3);
		// Change State
		subject.setState(300);
		System.out.println("obs1 Observer's MyState The status value is:"+obs1.getMyState());
		System.out.println("obs2 Observer's MyState The status value is:"+obs2.getMyState());
		System.out.println("obs3 Observer's MyState The status value is:"+obs3.getMyState());
		// Change State
		subject.setState(400);
		System.out.println("obs1 Observer's MyState The status value is:"+obs1.getMyState());
		System.out.println("obs2 Observer's MyState The status value is:"+obs2.getMyState());
		System.out.println("obs3 Observer's MyState The status value is:"+obs3.getMyState());
	}
}

That's the end of the article. Yes, it's gone

If it's not necessary, just prepare the above nine design patterns. It's a little difficult to remember them all


 

Tags: Java Design Pattern Interview

Posted by FUEL on Sun, 24 Jul 2022 05:32:50 +0930