Learn from me the factory mode of design mode

The Factory mode is widely used. It can be seen everywhere in the JDK underlying source code and major mainstream frameworks. Generally, classes named after Factory, such as SqlSessionFactory in Mybatis and BeanFactory in Spring, are typical representatives of the Factory mode.

I. simple factory mode

1.1 concept

Simple factory pattern, also known as static factory pattern, belongs to the creation pattern in design pattern. The simple factory pattern provides a static method to create instances for classes. The purpose is to decouple the classes: the client does not need to know how the object is created, but only needs to call the method of simple factory pattern to create it uniformly, so as to clarify the responsibilities of each class.

1.2 example

Simple factory mode, take the production of automobile tires as an example.

1.2.1 entity class

  • Tire general properties
public class Tire {
    /**
     * General attribute
     */
    private String common;
}
  • Mercedes tires

It contains its own special properties in addition to the general properties

public class TireForBenz extends Tire{


    Tire tire;
    /**
     * Specific attributes
     */
    private String benz;

    public TireForBenz() {
        this.benz = "obtain Benz tyre";
    }


    @Override
    public String toString() {
        return "["+this.benz +"]";
    }
}
  • BMW tires

It contains its own special properties in addition to the general properties

public class TireForBwm extends Tire{

    Tire tire;

    /**
     * Specific attributes
     */
    private String bwm;

    public TireForBwm() {
        this.bwm = "obtain Bwm tyre";
    }

    @Override
    public String toString() {
        return "["+this.bwm +"]";
    }
}

1.2.2 production process

  • Abstract method of tire production, each production line has its own way of production
public interface TireFactory {

    Tire produceTire();
}
  • Benz tire production line

Rewrite the method of producing tire to return Benz tire.

public class BenzTireFactory implements TireFactory {

    /**
     * Production of Benz tire
     */
    @Override
    public Tire produceTire() {
        System.out.println("Mercedes tire production...");
        return new TireForBenz();
    }
}
  • BMW tire production line

Overriding the method of producing a tire returns a BMW tire.

public class BwmTireFactory implements TireFactory {

    /**
     * Production of BMW tires
     */
    @Override
    public TireForBwm produceTire() {
        System.out.println("BMW tire production...");
        return new TireForBwm();
    }
}

1.2.3 tire factory

Call the corresponding production line to produce the corresponding brand tires through the incoming brand name

public class SimpleFactoryMode {

    public static TireFactory produceCar(String name) {
        if ("BenzTireFactory".equals(name)) {
            return new BenzTireFactory();
        }
        if ("BwmTireFactory".equals(name)) {
            return new BwmTireFactory();
        }
        return null;
    }
}

1.2.4 test

The client obtains the instance object through the factory class.

  • test method
 @Test
public void simpleFactoryModeTest() {
    // Make Benz tire
    TireFactory benz = SimpleFactoryMode.produceCar("BenzTireFactory");
    if (null != benz) {
        benz.produceTire();
    }else {
        System.out.println("The factory is temporarily unable to produce Mercedes Benz tires");
    }
    // Make BMW tires
    TireFactory bwm = SimpleFactoryMode.produceCar("BwmTireFactory");
    if (null != bwm) {
        bwm.produceTire();
    }else {
        System.out.println("The factory is temporarily unable to produce BMW tires");
    }
    // Honda tire manufacturing (the factory does not have this method)
    TireFactory honda = SimpleFactoryMode.produceCar("Honda");
    if (null != honda) {
        honda.produceTire();
    }else {
        System.out.println("The factory is temporarily unable to produce Honda tires");
    }
}
  • Result
Mercedes tire production...
BMW tire production...
The factory is temporarily unable to produce Honda tires

This method can complete tire production of different brands, but there is a problem: the method parameters are strings, and the controllability needs to be improved.

1.3 simple plant model optimization

Don't judge the object to be created by the incoming string, but what the client wants to create. Just pass in the specific implementation class, and then create the object by Java reflection.

public static TireFactory produceCar(Class<? extends TireFactory> clazz) {
    try {
        // Creating objects through Java reflection
        return clazz.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

Every time an object is created, it is created by reflection, so there is a certain loss in performance.

  • test
public void simpleFactoryModeUpgradeTest() {
    // Make Benz tire
    TireFactory benzTire = SimpleFactoryMode.produceCar(BenzTireFactory.class);
    TireForBenz benz = (TireForBenz) benzTire.produceTire();
    System.out.println(benz.toString());
    // Make BMW tires
    TireFactory bwmTire = SimpleFactoryMode.produceCar(BwmTireFactory.class);
    TireForBwm bwm = (TireForBwm) bwmTire.produceTire();
    System.out.println(bwm.toString());
}
  • Result
Mercedes tire production...
[get Benz tires]
BMW tire production...
[get Bwm tires]

1.4 summary

The simple factory pattern does decouple the code to a certain extent, and the characteristic of this decouple is that this pattern separates the creation and use of objects. The essence of this pattern is to return different types of objects by making if...else judgment with an incoming parameter. The shortcomings are obvious, not in line with Opening and closing principle (for example, for the production of a new Porsche tire, in addition to the entity and production method, the factory class SimpleFactoryMode.java needs to be modified.). Therefore, if you need to add new types, you have to modify the original code, in violation of the opening and closing principle.

  • Advantages of simple factory mode:
  1. The software architecture is simply optimized, and the responsibilities and rights of each functional module are defined;
  2. Through the factory class, the outside world does not need to directly create specific product objects, only needs to be responsible for consumption, and does not need to care about how to create objects internally.
  • Disadvantages of simple factory mode:
  1. Before the improvement, all the creation logic of the simple factory pattern was concentrated in one factory class, and the classes that can be created can only be considered. If a new class needs to be added, the factory class must be changed;
  2. With the continuous increase of specific products, the simple factory mode before improvement may meet the needs of Communist class to create different instances according to different conditions. This judgment of conditions and judgment of specific product types are interlaced, so it is difficult to avoid the spread of functional modules, which is not conducive to the maintenance and expansion of the system;
  3. The improved simple factory mode mainly uses lower reflection efficiency.

II. Factory method mode

  • What is the key to the violation of the opening and closing principle of the simple factory mode?

That is, it concentrates the creation of all objects in the same factory class. Therefore, when a new object is added, the shared factory class must be modified. It is inevitable to violate the opening and closing principles.

  • Solution

Since the key to the problem is that the creation of all objects is coupled with this unique factory class, each object of mine is configured with a separate factory class, and this factory class only creates objects of its own type, then won't this solve the problem of coupling?

2.1 concept

Factory method pattern is to define an interface to create an object, but let the class that implements the interface decide which class to instantiate. Factory methods delay class instantiation to subclasses. In the factory method mode, users only need to care about the corresponding factory of the required products, not about the creation details, and add new products in line with the opening and closing principle.

2.2 example

Factory method mode, take engine production as an example.

2.2.1 entity

  • General properties of the engine
public class Engine {

    /**
     * Model
     */
    private String common;

}
  • BENZ Engine

It contains its own special properties in addition to the general properties

public class EngineForBenz extends Engine{

    Engine engine;
    /**
     * Specific attributes
     */
    private String benz;

    public EngineForBenz() {
        this.benz = "obtain Benz Engine";
    }

    @Override
    public String toString() {
        return "["+this.benz +"]";
    }
}
  • BMW engine

It contains its own special properties in addition to the general properties

public class EngineForBwm extends Engine{

    Engine engine;
    /**
     * Specific attributes
     */
    private String bwm;

    public EngineForBwm() {
        this.bwm = "obtain Bwm Engine";
    }

    @Override
    public String toString() {
        return "["+this.bwm +"]";
    }
}

2.2.2 production process (factory type of engine)

  • Abstract factory class, define the method of production engine, and implement by each production line
public interface EngineFactory<T> {

    Engine produceEngine();

}
  • Establish Benz sub factory and realize its technology
public class BenzEngineFactory implements EngineFactory<EngineForBenz> {

    /**
     * Production of BENZ Engine
     */
    @Override
    public Engine produceEngine() {
        System.out.println("Mercedes Benz engine production...");
        return new EngineForBenz();
    }
}
  • Create BMW sub factory and realize its technology
public class BwmEngineFactory implements EngineFactory<EngineForBwm> {

    /**
     * Production of BMW engines
     */
    @Override
    public Engine produceEngine() {
        System.out.println("BMW engine production...");
        return new EngineForBwm();
    }
}

2.2.3 test

@Test
public void factoryModeTest() {
    // Build BENZ Engine
    EngineFactory car = new BenzEngineFactory();
    EngineForBenz benz = (EngineForBenz) car.produceEngine();
    System.out.println(benz.toString());
    // Make BMW engine
    EngineFactory carFactory = new BwmEngineFactory();
    EngineForBwm bwm = (EngineForBwm) carFactory.produceEngine();
    System.out.println(bwm.toString());
}
  • Result
In the production of BENZ Engine...
[get the Benz Engine]
BMW engine production...
[get Bwm engine]

2.3 summary

The factory method mode solves the problem of simple factory mode easily and conforms to the principle of opening and closing. In the above example, when you need to add a new Porsche car, you only need to provide a corresponding EngineForBSJ.java to implement the produceEngine() method, and you don't need to make any changes to the original code.

However, each type of object will have a corresponding factory class. If there are many types of objects, it means that a lot of factory implementation classes need to be created, which causes the expansion of the number of classes and causes some trouble for subsequent maintenance.

  • shortcoming
  1. The client (application layer) does not depend on the details such as how the product instance is created and implemented;
  2. A class specifies which object to create through its subclasses.
  • shortcoming
  1. The number of classes is easy to be too many, increasing the complexity;
  2. It increases the abstraction and understanding difficulty of the system.

3. Abstract factory model

The emergence of abstract factory pattern is to solve the problems of factory method pattern, which can be regarded as the upgrading of factory method pattern.

3.1 background

  • The scenario of class quantity expansion

The objects created by the factory method pattern are essentially the same kind of objects. Taking automobile production as an example, both tire and engine are part of automobile production and belong to the process of automobile production. The following picture:

From the above figure, we can see that although they are divided into Mercedes Benz and BMW, they all belong to the category of automobile from the perspective of factory method, which leads to the problem that each part needs to be specified with its own factory category, resulting in the expansion of category quantity.

  • Solution

In this case, we can designate a factory for each type of car, and then let different production lines produce the products he needs, as shown in the following figure

In this way, when the number of components of each kind of article is very large, it can be called product family. Abstract factory pattern is to create a series of objects based on product family, which can greatly improve development efficiency and reduce maintenance cost when a large number of series objects need to be created.

3.2 example

Because the entity of Benz tire / BMW tire / BENZ Engine / BMW engine has been created before, it is directly used here.

3.2.1 automobile factory class (top level abstract factory class)

This class already includes tire / engine production, specific entity key 1 / 2 related entities.

public interface CarFactory {

    /**
     * Ready for production
     */
    void init();

    /**
     * Tire production
     * @return
     */
    Tire produceTire();

    /**
     * Production engine
     * @return
     */
    Engine produceEngine();
}

3.2.2 Benz automobile product family (Benz automobile factory)

public class BenzCarFactory implements CarFactory{


    @Override
    public void init() {
        System.out.println("----------------------- Mercedes Benz ready for production -----------------------");
    }

    @Override
    public Tire produceTire() {
        System.out.println("Benz tire is being produced");
        return new TireForBenz();
    }

    @Override
    public Engine produceEngine() {
        System.out.println("Benz engine is being produced");
        return new EngineForBenz();
    }
}

3.2.2 BMW product family (BMW factory)

public class BwmCarFactory implements CarFactory{


    @Override
    public void init() {
        System.out.println("----------------------- BMW ready for production -----------------------");
    }

    @Override
    public Tire produceTire() {
        System.out.println("BMW tires are being produced");
        return new TireForBwm();
    }

    @Override
    public Engine produceEngine() {
        System.out.println("BMW engine in production");
        return new EngineForBwm();
    }
}

3.2.3 test

@Test
public void abstractFactoryModeTest() {
    // Production of parts for Mercedes Benz
    CarFactory benz = new BenzCarFactory();
    benz.init();
    TireForBenz benzTire = (TireForBenz) benz.produceTire();
    System.out.println(benzTire.toString());

    EngineForBenz benzEngine = (EngineForBenz) benz.produceEngine();
    System.out.println(benzEngine.toString());

    // Generate BMW parts d
    CarFactory bwm = new BwmCarFactory();
    bwm.init();
    TireForBwm bwmTire = (TireForBwm) bwm.produceTire();
    System.out.println(bwmTire.toString());

    EngineForBwm bwmEngine = (EngineForBwm) bwm.produceEngine();
    System.out.println(bwmEngine.toString());
}
  • Result
-----------------------Mercedes Benz ready for production-----------------------
Benz tire is being produced
 [get Benz tires]
Benz engine is being produced
 [get the Benz Engine]
-----------------------BMW ready for production-----------------------
BMW tires are being produced
 [get Bwm tires]
BMW engine in production
 [get Bwm engine]

3.3 thinking

Since abstract factory pattern is the upgrade of factory method pattern, what has been upgraded?

In fact, it is the production upgrading of the original single product to the production of a series of products. Let's imagine that in the example of the above car, only one component is produced in each brand of car, for example, only the engine is produced, and other components such as tires are not produced, as shown in the following figure

Did you find anything? The abstract factory model has been transformed into the factory method model we talked about before! In other words, when you only produce one product in your product family, your abstract factory pattern has actually degenerated into a factory method pattern. On the other hand, when many kinds of products are produced, the factory method pattern evolves into the abstract factory pattern.

3.4 summary

Abstract factory pattern can greatly improve the development efficiency when creating a large number of series of objects, which is generated for the production of product families, but can't do anything for the production of a single product.

If you need to add a new product family, it's easy. For example, if you want to add a Porsche car, you only need to add a factory implementation class of Porsche car, which will not affect the original code.

However, if I need to add another component in the car, such as reversing image, how to operate? You need to add an interface to the CarFactory interface to return the reverse image object. This is a great addition... All the brand car implementation classes need to modify and add the implementation of this method, which violates the opening and closing principle.

  • Advantages of abstract factory mode:

Creating a large number of series of objects can greatly improve the development efficiency and reduce the maintenance cost.

  • Disadvantages of abstract factory mode:
  1. It defines all product sets that may be created. It is difficult to expand new products in the product family, and the interface of the abstract factory needs to be modified;
  2. It increases the abstraction and understanding difficulty of the system.

Four, summary

4.1 how to choose

The three forms of factory model are introduced, so how to choose in our actual development?

  1. In terms of design principles, the simple plant mode does not conform to the opening and closing principles. But it's amazing. In the actual scene, the simple factory mode is actually used the most.
  2. The factory method pattern is designed to solve the problem of creating a single object. The pattern itself has no problem and conforms to the principle of opening and closing. But there is the problem of factory class quantity expansion. If not many factory classes need to be created, it is a good choice.
  3. Abstract factory pattern is born to produce product families. So if you need to create a lot of objects, but there are obvious product family features between the objects, then it is appropriate to use the abstract factory pattern at this time.

4.2 sample source code

Github sample code

4.3 technical exchange

  1. FengChen blog: https://www.dustyblog.cn
  2. Dust blog - gold digger
  3. FengChen blog blog Garden
  4. Github
  5. official account


Reference articles

Tags: Java github JDK Mybatis

Posted on Tue, 03 Dec 2019 18:00:17 -0500 by Evoke