Java Design Patterns (update…)

1. Singleton

  • How do YOU implement singletons?

    We usually get the instance directly through new because the class has no parameter constructor by default. However, creating an instance with new allows you to create multiple instances, whereas singleton creates only one instance. Therefore, we make the constructor private so that other classes cannot create the instance directly from the constructor

  • applications

    When you don’t need to create multiple objects (instances), you can use the singleton pattern to ensure that there is only one object (instance) in the entire application. Such as log files, thread pools, database connection pools, etc.

1.1 Hangry singleton

  • What is hungrier mode?

    Create a unique instance of a class when it is loaded (you can interpret it as being hungry and hungry, so create an instance as soon as the class is loaded)

  • Code:

    / * * *@program: soft_test
     * @description: singleton mode - Hungry *@author: Mr.zuo
     * @create: "* * / 2021-02-17
    
    public class HungrySingleton {
        /** * 1. Privatize the constructor * Purpose: To disallow object creation between external classes ** /
        private HungrySingleton(a){}/** *2. Create an instance of a singleton class ** /
        private static HungrySingleton instance = new HungrySingleton();
    
        /** * 3. Provide a method to obtain the instance ** purpose: After making the instance private, provide a public method for external calls to obtain the instance ** /
        public static HungrySingleton getInstance(a){
            returninstance; }}/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    
    / * * *@program: soft_test
     * @description: Hangry singleton test *@author: Mr.zuo
     * @create: the 2021-02-17 22:33 * * /
    
    public class HungrySingletonTest {
        public static void main(String[] args) {
            HungrySingleton singleton1 = HungrySingleton.getInstance();
            HungrySingleton singleton2 = HungrySingleton.getInstance();
            if (singleton1 == singleton2){
                System.out.println("For the same instance object");// true
            }else {
                System.out.println("For different instance objects");// false}}}Copy the code
  • The characteristics of

    1. Thread safety

    2. Class loading creates an object, which is slower than lazy, but faster to call

1.2 Lazy singleton

  • What is a lazy singleton?

    Instance objects of the class are not created immediately when the class is loaded, but only when the object needs to be called. (You can understand that I’m lazy; I procrastinate. When I create class objects, I don’t want to instantiate them first, only when I need them.)

  • code

    / * * *@program: soft_test
     * @description: lazy singleton *@author: Mr.zuo
     * @create: so * * / 2021-02-17
    
    public class LazySingleton {
        /** * 1. Privatize the constructor to avoid creating objects directly from external classes ** /
        private LazySingleton(a){}
    
        /** * 2. Use the private,static modifier, but do not directly create the instance ** /
        private static LazySingleton instance;
    
        /** * 3. Provide a method to call the instance, create the instance when it is first fetched, otherwise return the instance ** /
        public static LazySingleton getInstance(a){
            if (instance == null){
                instance = new LazySingleton();
            }
            returninstance; }}/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    
    / * * *@program: soft_test
     * @description: lazy singleton tests *@author: Mr.zuo
     * @create: the 2021-02-17 after * * /
    
    public class LazySingletonTest {
        public static void main(String[] args) {
            LazySingleton singleton1 = LazySingleton.getInstance();
            LazySingleton singleton2 = LazySingleton.getInstance();
            if (singleton1 == singleton2){
                System.out.println("For the same instance");// true
            }else {
                System.out.println("For a different instance");// false}}}Copy the code
  • The characteristics of

    1. Threads are unsafe

    2. It is faster to load the class, but slower to call the class

1.3 Double-check Mode — Recommended (Most Commonly used)

  • What is double-checked mode?

    At most, double checking is required when an external class needs to create an instance of that class.

  • Why double check?

    Double-checked mode ensures thread-safety and lazy initialization (that is, lazy mode), while optimizing performance

  • code

    / * * *@program: soft_test
     * @description: Double-checked mode *@author: Mr.zuo
     * @create: the 2021-02-17 and * * /
    
    public class DoubleCheckSingleton {
    
        /** * privatize the constructor ** /
        private DoubleCheckSingleton(a){}
    
        /** * volatile modifier: disables instruction reordering ** /
        private volatile static DoubleCheckSingleton instance;
    
        public static DoubleCheckSingleton getInstance(a){
            // Reduce do not synchronize, optimize performance
            if (instance == null) {// Synchronize to ensure thread safety
                synchronized (DoubleCheckSingleton.class){
                    if (instance == null) {// Create an instance
                        instance = newDoubleCheckSingleton(); }}}returninstance; }}/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
    
    / * * *@program: soft_test
     * @description: double-checked singleton pattern test *@author: Mr.zuo
     * @createYou: 2021-02-17 * * /
    
    public class DoubleCheckSingletonTest {
        public static void main(String[] args) {
            DoubleCheckSingleton singleton1 = DoubleCheckSingleton.getInstance();
            DoubleCheckSingleton singleton2 = DoubleCheckSingleton.getInstance();
            if (singleton1 == singleton2){
                System.out.println("Same instance object");// true
            }else {
                System.out.println("Instance object is different");//false}}}Copy the code
  • The characteristics of

    1. Delay initialization. Consistent with lazy mode, the Signleton instance is initialized only on the first call to the static method getSingleton.

    2. Performance optimization. Synchronization can degrade performance, so check whether the Singleton is initialized before synchronization to reduce unnecessary synchronization overhead.

    3. Thread safety. Create the Singleton object synchronously, noting that the static Singleton variable uses the volatile modifier.

1.4 Static inner Class pattern — recommended

  • What is the static inner class schema?

    Create a singleton pattern using the methods of static inner classes

  • Why use the static inner class pattern?

    Code concise, ensure thread safety, and delay initialization

  • code

    / * * *@program: soft_test
     * @description: Static inner class schema *@author: Mr.zuo
     * @createShall: the 2021-02-17 * * /
    
    public class StaticSingleton {
        private StaticSingleton(a){}
        public static StaticSingleton getInstance(a){
            return Inner.instance;
        }
        public static class Inner{
            private static final StaticSingleton instance = newStaticSingleton(); }}/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = / /
    
    / * * *@program: soft_test
     * @description: Static inner class schema testing *@author: Mr.zuo
     * @create: the 2021-02-17 thou * * /
    
    public class StaticSingletonTest {
        public static void main(String[] args) {
            StaticSingleton singleton1 = StaticSingleton.getInstance();
            StaticSingleton singleton2 = StaticSingleton.getInstance();
            if (singleton1 == singleton2){
                System.out.println("For the same instance");// true
            }else {
                System.out.println("For a different instance");// false}}}Copy the code
  • The characteristics of

    1, the implementation of simple code. Compared to the double-checked singleton, the static inner class singleton implementation code is really neat and clean.

    2. Delay initialization. The Singleton object is initialized by calling getSingleton.

    3. Thread safety. During the initialization phase of a class, the JVM acquires a lock that can synchronize multiple threads’ initialization of the same class.

Reference:

Java: Singleton pattern I only recommend two

2. Six implementations of singleton pattern

3. Singleton interview questions

2. Factory Mode

2.1 What is factory mode?

A factory is, as the name suggests, a place to create products that are analogous to objects in Java. In general, we create objects with the new keyword, whereas with the factory pattern, we hand the objects to the factory, and we get the objects of the desired products directly from the factory. Factory pattern is divided into simple factory pattern (also known as static factory pattern), method factory pattern and abstract factory pattern.

2.2 Application Scenarios in Java

  • Create SqlSessionFactory, ObjectFactory, MapperProxyFactory in Mybatis
  • The BeanFactory creation in Spring is used to manage the Bean factory
  • The iterator method in Collection in the Jdk

2.3 Simple Factory Mode (Static Factory Mode)

2.3.1 generalization

Simple factory actual doesn’t count as a kind of design pattern, it introduced the concept of creator, instantiation of the code from application code, in static method of creator classes only deals with details for creating an object, subsequent firm needs to change, for example, just transform creator classes (i.e., the factory class) can, however, but as a result of using static method to get the object, It cannot dynamically change the creation behavior in different ways during runtime, so it has some limitations

First of all, let’s take building a car as an example. Suppose you want to buy a car, but there are many kinds of cars, and you don’t know which one to buy. You can go to the factory to see if there is a brand of car that you need.

2.3.2 The code is as follows

  • 1. Construct the abstract class of the car

/ * * *@program: soft_test
 * @descriptionBMW, Mercedes, Maserati, etc. are concrete examples of the car, while the car is just an abstract concept. *@author: Mr.zuo
 * @create: the 2021-02-24 17:31 * * /

public abstract class Car {
    /** ** Car name ** /
    abstract String name(a);
}
Copy the code

*2. Create a specific vehicle instance

/ * * *@program: soft_test
 * @description: Car - Benz *@author: Mr.zuo
 * @createCovenant: 2021-02-24 * * /

public class Benz extends Car{

    @Override
    String name(a) {
        String Benz = "Mercedes";
        returnBenz; }}/ * * *@program: soft_test
 * @description: Car - BMW *@author: Mr.zuo
 * @create: in the 2021-02-24 s when * * /

public class BMW extends Car{
    @Override
    String name(a) {
        String BMW="BMW";
        returnBMW; }}Copy the code
  • 3. Create car factories
/ * * *@program: soft_test
 * @description: Factory for creating cars *@author: Mr.zuo
 * @create: the 2021-02-24 saveth * * /

public class CarFactory {
    private static String BMW = "BMW";
    private static String Benz = "Mercedes";

    public static Car getCar(String car) {
        if (BMW.equals(car)) {
            return new BMW();
        } else if (Benz.equals(car)) {
            return new Benz();
        } else {
            return null; }}}Copy the code

CarFactory discovered that when new instances of cars need to be added, we need to modify the code found by CarFactory, which does not comply with the open and closed principle.

  • 4. Create a simple factory pattern
/ * * *@program: soft_test
 * @description: Simple Factory mode (static factory mode) - Used to produce any product in the same hierarchy (for adding new products, existing code needs to be overwritten) * Essence: Instead of using new to create powerful objects, use factory method to create * and select implementation classes to create objects for unified management and control. This decouples the caller from the implementation class * Disadvantages: not meeting the open and close principle, adding new objects requires modifying the code in CarFactory *@author: Mr.zuo
 * @create: the 2021-02-24 17:28 * * /

public class SimpleFactory {

    public static void main(String[] args) {
        /** * Create with factory - instantiate with CarFactory instead of new * traditional method: Benz Benz = new Benz(); * benz.name; * * /
        Car c1 = CarFactory.getCar("BMW");
        Car c2 = CarFactory.getCar("Mercedes"); System.out.println(c1.name()); System.out.println(c2.name()); }}Copy the code

2.3.3 Advantages of the simple factory model

  • The factory class contains the necessary judgment logic to decide when to create an instance of a product class, freeing clients from the responsibility of directly creating product objects and simply “consuming” the product; The simple factory pattern achieves this separation of responsibilities by providing specialized factory classes for creating objects.
  • The client does not need to know the class name of the created specific product class, but only needs to know the corresponding parameters of the specific product class. For some complex class names, simple factory mode can reduce the memory of users.
  • By introducing configuration files, new specific product classes can be replaced and added without modifying any client code, increasing the flexibility of the system to some extent.

2.3.4 Disadvantages of the simple factory pattern

  • Because the factory class centralizes all product creation logic, if it doesn’t work properly, the entire system suffers.
  • Using the simple factory pattern will increase the number of classes in the system, increasing the complexity and understanding of the system at some point.
  • It is difficult to expand the system. Once new products are added, the factory logic has to be modified. If there are many product types, the factory logic may be too complex, which is not conducive to the expansion and maintenance of the system.
  • The simple factory pattern uses a static factory approach that prevents the factory roles from forming an inheritance-based hierarchy.

2.3.5 Application Scenarios

  • The factory class is responsible for creating fewer objects: Because there are fewer objects created, the business logic in the factory method is not too complicated.
  • The client only knows the parameters passed into the factory class, not how the object is created: the client doesn’t need to care about the creation details or even remember the class name, just the parameters that the type corresponds to.

2.4 Factory method pattern

Against 2.4.1 preface

According to the simple factory mode mentioned above, we can know that its disadvantage is that it does not abide by the closed and open principle, so the factory method mode is proposed. Each instance of the abstract Car class corresponds to its own factory, which creates an instance of the Car of the product and then takes it to the CarFactory. The user only needs to get the instance of the class from the CarFactory.

2.4.2 The code is as follows

Note: the car instances and abstract car classes are unchanged, as described above, so they are not reused here.

  • Factory class for abstract class CAR
/ * * *@program: soft_test
 * @description:
 * @author: Mr.zuo
 * @create: the 2021-02-24 and * * /

public abstract class CarFactory {
    /** * Returns an array of Car types. * For example, BMW series cars include BMW X6, BMW X7, AND BMW Sports car, all of which are created by the factories that manufacture BMW. * * /
    abstract Car[] getCar();
}
Copy the code
  • Specific class Benz,BWM factory class
/ * * *@program: soft_test
 * @description: To build a factory for Mercedes@author: Mr.zuo
 * @create: "* * / 2021-02-24

public class BenzFactory extends CarFactory{
    @Override
    public Car[] getCar() {
        return new Car[]{newBenz()}; }}/ * * *@program: soft_test
 * @description: BMW Factory - Create BMW *@author: Mr.zuo
 * @create: the 2021-02-24 18:47 * * /

public class BMWFactory extends CarFactory{

    @Override
    public Car[] getCar() {
        return new Car[]{newBMW()}; }}Copy the code
  • Create the factory method pattern
/ * * *@program: soft_test
 * @description: Factory method pattern - Defines an interface for creating objects, * but leaves it up to subclasses to decide which class to instantiate. Factory methods leave class instantiation to subclasses *@author: Mr.zuo
 * @create: the 2021-02-24 17:28 * * /

public class SimpleFactory {

    public static void main(String[] args) {
        Car[] car1 = new BenzFactory().getCar();
        for (Car car : car1) {
            System.out.println(car.name());
        }
        Car[] car2 = new BMWFactory().getCar();
        for(Car car : car2) { System.out.println(car.name()); }}}Copy the code

2.4.3 Advantages of factory method mode

  • In the factory method pattern, the factory method is used to create the product that the customer needs, and it also hides the details of which specific product class will be instantiated from the customer. The user only needs to care about the factory for the desired product, not the creation details, or even the class name of the specific product class.
  • The polymorphism design based on factory role and product role is the key of factory method pattern. It enables the factory to decide which product object to create, and the details of how to create this object are completely encapsulated within the specific factory. The factory method pattern is also called polymorphic factory pattern because all concrete factory classes have the same abstract parent class.
  • Another advantage of using the factory method pattern is that when you add a new product to the system, you don’t need to modify the abstract factory and the interface provided by the abstract product, you don’t need to modify the client, or you don’t need to modify other concrete factories and concrete products, you just need to add a concrete factory and concrete products. In this way, the scalability of the system has become very good, fully in line with the “open and closed principle”.

2.4.4 Disadvantages of the factory method pattern

  • When adding new products, it is necessary to write new concrete product classes and provide corresponding concrete factory classes. The number of classes in the system will increase in pairs, which increases the complexity of the system to a certain extent. More classes need to be compiled and run, which will bring some extra overhead to the system.
  • Considering the scalability of the system, it is necessary to introduce an abstraction layer, which is defined in the client code, increasing the abstractness and difficulty of understanding of the system, and DOM, reflection and other technologies may be used in the implementation, increasing the difficulty of the implementation of the system.

2.4.5 Application Scenarios

  • A class does not know the class of the object it needs: in the factory method pattern, the client does not need to know the class name of the specific product class, only the corresponding factory. The specific product object is created by the specific factory class. The client needs to know the factory class to create the specific product.
  • A class through its subclasses to specify which object to be created, in the factory method pattern, for the abstract factory class only need to provide an interface for creating products, and by its subclasses to determine specific to create the object, using the object-oriented polymorphism and magnitude of substitution principle, when the program is run by a subclass overrides the superclass object, so as to make the system more scalable.
  • Delegate the task of creating objects to one of multiple factory subclasses. The client can use it without worrying about which factory subclass creates the product subclass and specify it dynamically when necessary. The class name of the specific factory class can be stored in the configuration file or database.

2.5 Abstract factory pattern

2.5.1 generalization

For example, Xiaomi and Huawei make mobile phones as well as routers and other products. The Xiaomi factory manages the Xiaomi factory that makes phones and routers, the Xiaomi phone factory that makes phones, and the Xiaomi Router factory that makes routers. So this leads to a conceptual product family. In this case, the different products make up our abstract product factory, and the abstract product factory starts to take on the responsibility of the creator to make different products.

2.5.2 The code is as follows

  • Phone and router product interface
/ * * *@program: soft_test
 * @description: Mobile product interface *@author: Mr.zuo
 * @create: the 2021-02-24 23:05 * * /

public interface IphoneProduct {
    void startPhone(a);
    void shutdown(a);
    void callup(a);
    void sendSMS(a);
}


/ * * *@program: soft_test
 * @description: Router product interface *@author: Mr.zuo
 * @create: the 2021-02-24 23:07 * * /

public interface IRouterProduct {
    void startRouter(a);
    void shutdown(a);
    void openwifi(a);
    void setting(a);
}
Copy the code
  • Mobile phone and router concrete implementation classes
/ * * *@program: soft_test
 * @description: Xiaomi phone *@author: Mr.zuo
 * @create: the 2021-02-24 23:09 * * /

public class XiaomiPhone implements IphoneProduct{

    @Override
    public void startPhone(a) {
        System.out.println("Xiaomi Startup");
    }

    @Override
    public void shutdown(a) {
        System.out.println("Xiaomi Shutdown");
    }

    @Override
    public void callup(a) {
        System.out.println("Xiaomi Calls");
    }

    @Override
    public void sendSMS(a) {
        System.out.println("Xiaomi texting"); }}/ * * *@program: soft_test
 * @description: Huawei mobile phone *@author: Mr.zuo
 * @create: the 2021-02-24 masters * * /

public class HuaweiPhone implements IphoneProduct{

    @Override
    public void startPhone(a) {
        System.out.println("Huawei startup");
    }

    @Override
    public void shutdown(a) {
        System.out.println("Huawei shutdown");
    }

    @Override
    public void callup(a) {
        System.out.println("Huawei calls");
    }

    @Override
    public void sendSMS(a) {
        System.out.println("Huawei texting"); }}/ * * *@program: soft_test
 * @description: Xiaomi Router *@author: Mr.zuo
 * @create: the 2021-02-24 and * * /

public class XiaomiRouter implements IRouterProduct{
    @Override
    public void startRouter(a) {
        System.out.println("Mi Router startup");
    }

    @Override
    public void shutdown(a) {
        System.out.println("Xiaomi Router shutdown");
    }

    @Override
    public void openwifi(a) {
        System.out.println("Xiaomi Router turns on wifi");
    }

    @Override
    public void setting(a) {
        System.out.println("Xiaomi Router Settings"); }}/ * * *@program: soft_test
 * @description: Huawei router *@author: Mr.zuo
 * @create: now * * / 2021-02-24

public class HuaweiRouter implements IRouterProduct{
    @Override
    public void startRouter(a) {
        System.out.println("Huawei Router startup");
    }

    @Override
    public void shutdown(a) {
        System.out.println("Huawei router shutdown");
    }

    @Override
    public void openwifi(a) {
        System.out.println("Huawei Router turns on wifi");
    }

    @Override
    public void setting(a) {
        System.out.println("Huawei Router Settings"); }}Copy the code
  • Abstract product factory sells mobile phones and routers (production is produced by its own factory)
/ * * *@program: soft_test
 * @descriptionAbstract product factory *@author: Mr.zuo
 * @create: the 2021-02-24 hands * * /

public interface AbstractProductFactory {
    // Make mobile phones
    IphoneProduct  phoneProduct(a);
    // Create a router
    IRouterProduct  routerProduct(a);
}
Copy the code
  • The specific factory that produces the product
/ * * *@program: soft_test
 * @description: Xiaomi Factory - Used to produce Xiaomi products *@author: Mr.zuo
 * @create: let * * / 2021-02-24

public class XiaomiFactory implements AbstractProductFactory{
    @Override
    public IphoneProduct phoneProduct(a) {
        return new XiaomiPhone();
    }

    @Override
    public IRouterProduct routerProduct(a) {
        return newXiaomiRouter(); }}/ * * *@program: soft_test
 * @description: Huawei Factory - Used to manufacture Huawei products *@author: Mr.zuo
 * @create: let * * / 2021-02-24

public class HuaweiFactory implements AbstractProductFactory{
    @Override
    public IphoneProduct phoneProduct(a) {
        return new HuaweiPhone();
    }

    @Override
    public IRouterProduct routerProduct(a) {
        return newHuaweiRouter(); }}Copy the code
  • Create an abstract factory pattern
/ * * *@program: soft_test
 * @description:
 * @author: Mr.zuo
 * @create: "* * / 2021-02-24

public class AbstractFactory {
    public static void main(String[] args) {
        System.out.println("==== Xiaomi products ====");
        XiaomiFactory xiaomiFactory = new XiaomiFactory();
        IphoneProduct phoneProduct = xiaomiFactory.phoneProduct();
        phoneProduct.callup();
        phoneProduct.sendSMS();
        IRouterProduct routerProduct = xiaomiFactory.routerProduct();
        routerProduct.openwifi();
        routerProduct.setting();
        System.out.println("==== Huawei products ====");
        HuaweiFactory huaweiFactory = newHuaweiFactory(); IphoneProduct iphoneProduct = huaweiFactory.phoneProduct(); iphoneProduct.sendSMS(); huaweiFactory.routerProduct().openwifi(); }}Copy the code

2.5.3 Advantages of abstract factory

  • The abstract factory pattern isolates the generation of concrete classes so that customers do not need to know what is being created. Because of this isolation, it is relatively easy to change a specific plant. All concrete factories implement the common interfaces defined in the abstract factory, so simply changing an instance of the concrete factory can change the behavior of the entire software system to some extent. In addition, abstract factory pattern can achieve high cohesion and low coupling design purpose, so abstract factory pattern has been widely used.
  • When multiple objects in a product family are designed to work together, it ensures that clients always use only objects in the same product family. This is a very useful design pattern for software systems that need to determine their behavior based on the current environment.
  • It is convenient to add new specific factories and product families without modifying existing systems, in accordance with the “open closed principle”.

2.5.4 Disadvantages of abstract factory

  • In object, add new products to extend the abstract factory to produce new kinds of products, all this is because the rules in the role of the abstract factory can be created product collection, new kinds of products to support means extensions to the interface, and this will involve the role of the abstract factory and all its subclasses change, obviously brings great inconvenience.
  • The inclination of the open and close principle (easy to add new factories and product families, troublesome to add new product grade structures).

2.5.5 Application Scenarios

  • It is important for all types of factory patterns that a system should not depend on the details of how product class instances are created, combined, and expressed.
  • There is more than one product family in the system and only one of them is used at a time.
  • Products belonging to the same product family will be used together, and this constraint must be reflected in the design of the system.
  • The system provides a library of product classes, all of which appear in the same interface, so that the client is implementation-independent.

Note: For the abstract factory pattern, personal feeling is relatively more difficult to understand the other two (anyway I didn’t understand) is the first time, but fortunately I refer to the following article gives me a lot of help, let me know the factory pattern, for the abstract factory pattern personal feeling is not so deep so rarely join personal understanding, is the reference basically used easy to let me understand the content of the article, I admit that this method is not good for personal improvement and irresponsible for readers, but writing abstract factory mode is really too painful psychologically and for physical reasons. I hope readers who read this article can understand, I will continue to make efforts to encourage each other.

Reference:

1. JAVA Design Pattern Factory Pattern (three factory patterns)

2. Create the factory mode of the pattern

3. Easy to understand the teaching of 23 design modes

4. Factory Model — Just read this one