Factory mode is widely used, and can be seen everywhere in JDK low-level source code and major mainstream frameworks. Classes usually named after Factory, such as SqlSessionFactory in Mybatis and BeanFactory in Spring, are typical examples of factory mode.
1. Simple Factory Mode
1.1 Concepts
Simple factory mode, also known as static factory mode, is a creation mode in design mode.Simple Factory Mode unifies the creation of instances for classes by providing a static method outside to decouple the classes: the client does not need to know how the object was created, just invoke the method of Simple Factory Mode to unify the creation, thus clarifying the responsibilities of each class.
1.2 Example
Simple factory model, taking the production of car tires as an example.
1.2.1 Entity Class
- Tyre general properties
public class Tire { /** * Common Properties */ private String common; }
- Benz Wheel Tyres
Include common attributes but also have their own unique attributes
public class TireForBenz extends Tire{ Tire tire; /** * Unique Properties */ private String benz; public TireForBenz() { this.benz = "obtain Benz tyre"; } @Override public String toString() { return "["+this.benz +"]"; } }
- BMW Wheel Tyres
Include common attributes but also have their own unique attributes
public class TireForBwm extends Tire{ Tire tire; /** * Unique Properties */ private String bwm; public TireForBwm() { this.bwm = "obtain Bwm tyre"; } @Override public String toString() { return "["+this.bwm +"]"; } }
1.2.2 Production Technology
- An abstract method of producing tyres, each line of production has its own way of producing them
public interface TireFactory { Tire produceTire(); }
- Benz tire production line
Rewrite the tire production method to return to the Benz tire.
public class BenzTireFactory implements TireFactory { /** * Production of Benz Tires */ @Override public Tire produceTire() { System.out.println("Benz tyre production."); return new TireForBenz(); } }
- BMW tire line
Rewrite the tire production method to return the BMW type tire.
public class BwmTireFactory implements TireFactory { /** * Production of BMW tyres */ @Override public TireForBwm produceTire() { System.out.println("BMW tyre production."); return new TireForBwm(); } }
1.2.3 Tyre Factory Class
Produce tires of the appropriate brand by invoking the corresponding production line with the brand name passed in
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 Tires TireFactory benz = SimpleFactoryMode.produceCar("BenzTireFactory"); if (null != benz) { benz.produceTire(); }else { System.out.println("The factory is temporarily unable to produce Benz tires"); } // Making BMW tires TireFactory bwm = SimpleFactoryMode.produceCar("BwmTireFactory"); if (null != bwm) { bwm.produceTire(); }else { System.out.println("The factory is temporarily unable to produce BMW tyres"); } // Honda steam turbine (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
Benz tyre production. BMW tyre production. The factory is temporarily unable to produce Honda tires
This method can do tire production of different brands, but there is a problem: the method parameter is string, and the controllability needs to be improved.
1.3 Simple Factory Mode Optimization
Instead of passing in a string to determine what object needs to be created, the client simply passes in a specific implementation class and creates the object through 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 through reflection, so there is a certain loss of performance.
- test
public void simpleFactoryModeUpgradeTest() { // Make Benz Tires TireFactory benzTire = SimpleFactoryMode.produceCar(BenzTireFactory.class); TireForBenz benz = (TireForBenz) benzTire.produceTire(); System.out.println(benz.toString()); // Making BMW tires TireFactory bwmTire = SimpleFactoryMode.produceCar(BwmTireFactory.class); TireForBwm bwm = (TireForBwm) bwmTire.produceTire(); System.out.println(bwm.toString()); }
- Result
Benz tyre production. [Get Benz tires] BMW tyre production. [get Bwm tires]
1.4 Summary
Simple factory mode does decouple code to some extent, and this decoupling is characterized by the separation of object creation and use.The essence of this pattern is to return different types of objects by making if...else judgments with an incoming parameter.The disadvantage is also obvious and does not match Open and Close Principle (For example, adding a new production of Porsche tires will require modifications to the factory class SimpleFactoryMode.java in addition to adding entities and production methods).Therefore, if you need to add a new type, you will have to modify the original code, violating the open and close principle.
- Advantages of simple factory mode:
- Simply optimize the software architecture, clarify the responsibilities and rights of each module;
- Through the factory class, the outside world does not need to create specific product objects directly, only need to be responsible for consumption, and do not need to care about how objects are created internally.
- Disadvantages of simple factory mode:
- All the creation logic of the simple factory mode before the improvement is concentrated in one factory class. The classes that can be created can only be considered. If new classes need to be added, the factory class must be changed.
- With the increasing number of specific products, the simple factory mode before improvement may appear that the Communist class needs to create different instances according to different conditions. This kind of judgment of conditions and specific product types are interlaced, which makes it difficult to avoid the spread of function modules and is unfavorable for the maintenance and expansion of the system.
- The improved simple factory mode will mainly use less reflective efficiency.
II. Factory Method Mode
- What is the key to why the simple factory mode violates the open and close principle?
That is, it concentrates the creation of all objects in the same factory class. Therefore, when a new object is added, it is necessary to modify the shared factory class. Violation of the open and close principle is inevitable.
- Solution
Since the key to the problem is that all object creation is coupled to this unique factory class, each of my objects is configured with a separate factory class, which only creates its own type of object. Does that solve the coupling problem?
2.1 Concepts
The factory method pattern refers to defining an interface that creates objects but lets the class that implements the interface decide which class to instantiate.Factory methods defer instantiation of classes to subclasses.In the factory method mode, the user only needs to care about the factory corresponding to the desired product, no need to care about the details of creation, and adding new products conforms to the open and close principle.
2.2 Example
Factory method mode, taking engine production as an example.
2.2.1 Entities
- General properties of engines
public class Engine { /** * Model */ private String common; }
- Benz Engine
Include common attributes but also have their own unique attributes
public class EngineForBenz extends Engine{ Engine engine; /** * Unique Properties */ private String benz; public EngineForBenz() { this.benz = "obtain Benz Engine"; } @Override public String toString() { return "["+this.benz +"]"; } }
- BMW Engine
Include common attributes but also have their own unique attributes
public class EngineForBwm extends Engine{ Engine engine; /** * Unique Properties */ private String bwm; public EngineForBwm() { this.bwm = "obtain Bwm Engine"; } @Override public String toString() { return "["+this.bwm +"]"; } }
2.2.2 Production Technology (Engine Factory Class)
- Abstract factory class, defining the way to produce engines, each line of production to its own implementation
public interface EngineFactory<T> { Engine produceEngine(); }
- Create Benz Subfactory to Realize Its Process
public class BenzEngineFactory implements EngineFactory<EngineForBenz> { /** * Production Benz Engine */ @Override public Engine produceEngine() { System.out.println("Benz Engine Production."); return new EngineForBenz(); } }
- Create a BMW sub-factory to implement its process
public class BwmEngineFactory implements EngineFactory<EngineForBwm> { /** * Making 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()); // Making BMW Engines EngineFactory carFactory = new BwmEngineFactory(); EngineForBwm bwm = (EngineForBwm) carFactory.produceEngine(); System.out.println(bwm.toString()); }
- Result
Benz Engine Production. [Get Benz engine] BMW Engine Production. [get Bwm engine]
2.3 Summary
The factory method mode easily solves the problem of simple factory mode and conforms to the principle of opening and closing.In the example above, when you need to add a new Porsche car, you just need to provide a corresponding EngineForBSJ.java implementation of produceEngine() without any modifications 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 many factory implementation classes will need to be created, causing the number of classes to expand and causing some difficulties for subsequent maintenance.
- shortcoming
- The client (application layer) does not depend on details such as how product class instances are created and implemented.
- A class specifies which object to create through its subclasses.
- shortcoming
- It is easy to have too many classes, which increases the complexity.
- It increases the abstraction and difficulty of understanding the system.
3. Abstract Factory Mode
The abstract factory mode appears in order to solve the problems of the above factory method mode, it can be seen as an upgrade of the factory method mode.
3.1 Background
- Scenario of class number expansion
The objects created by the factory method pattern are essentially the same kind of objects.Take the automobile production as an example, whether it is tire or engine, it is part of automobile production and belongs to the process of automobile production.As follows:
From the figure above, we can see that although they are divided into Mercedes-Benz and BMW, they belong to the category of automobiles from the factory method point of view, which leads to the problem that each part needs to be assigned its own factory class, resulting in the expansion of the number of classes.
- Solution
In this case, we can assign a factory to each type of car and then have different lines of production to produce the products he needs, as shown in the following figure
In this way, when the number of components in each category is very large, it can be called a product family.The abstract factory model is designed to create a series of objects in the product family, which can greatly improve development efficiency and reduce maintenance costs when a large number of series of objects need to be created.
3.2 Example
Because the Mercedes-Benz tyre/BMW tyre/Mercedes-Benz engine/BMW engine entity has been created in the front, it is used directly here.
3.2.1 Automotive Factory Class (Top Abstract Factory Class)
This category already includes tire/engine production, the related entities in the specific entity key 1/2.
public interface CarFactory { /** * Prepare for production */ void init(); /** * Tyre production * @return */ Tire produceTire(); /** * Production Engine * @return */ Engine produceEngine(); }
3.2.2 Benz Automotive Product Family (Benz Automotive Factory Class)
public class BenzCarFactory implements CarFactory{ @Override public void init() { System.out.println("----------------------- Mercedes-Benz preparing for production -----------------------"); } @Override public Tire produceTire() { System.out.println("Benz tires are being produced"); return new TireForBenz(); } @Override public Engine produceEngine() { System.out.println("Benz engine in production"); return new EngineForBenz(); } }
3.2.2 BMW Automotive Product Family (BMW Automotive Factory Class)
public class BwmCarFactory implements CarFactory{ @Override public void init() { System.out.println("----------------------- BMW Automotive Preparation -----------------------"); } @Override public Tire produceTire() { System.out.println("BMW tires are being produced"); return new TireForBwm(); } @Override public Engine produceEngine() { System.out.println("Producing BMW engines"); return new EngineForBwm(); } }
3.2.3 Test
@Test public void abstractFactoryModeTest() { // Manufacture spare parts for 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 parts d for BMW 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
------------------------------------------------------------------------- Benz tires are being produced [Get Benz tires] Benz engine in production [Get Benz engine] ---------------------------------------BMW car preparation for production----------------------- BMW tires are being produced [get Bwm tires] Producing BMW engines [get Bwm engine]
3.3 Thinking
Since abstract factory mode is an upgrade of factory method mode, what exactly has been upgraded?
In fact, the original production of a single product has been upgraded to the production of a series of products.Imagine, for example, that in the car example above, only one component is produced for each brand of car, such as an engine, no tires and other components, as shown below.
Did you find anything?The abstract factory mode has changed to the factory method mode we talked about before!In other words, when you produce only one product in your product family, your abstract factory model has actually degenerated into a factory method model.Conversely, when multiple products are produced, the factory method pattern evolves into an abstract factory pattern.
3.4 Summary
The abstract factory model can greatly improve the efficiency of development when creating a large number of series of objects, which are created for the production of a product family, but not for the production of a single product.
If you need to add a new product family, it's easy, like adding a new Porsche car, then you just need to add a factory implementation class for Porsche cars, and it won't affect the original code at all.
But what if I assume I need another component in my car, such as the reverse image?You need to add an interface to the CarFactory interface that returns the reverse image object.That adds up... All brand car implementation classes need to modify and append the implementation of this method, which violates the on/off principle.
- The benefits of the abstract factory model are:
Creating a large number of series objects can greatly improve development efficiency and reduce maintenance costs.
- Disadvantages of abstract factory mode:
- It specifies all possible product collections to be created. It is difficult to expand new products in a product family and the interface of an abstract factory needs to be modified.
- It increases the abstraction and difficulty of understanding the system.
4. Summary
4.1 How to choose
All three forms of factory mode have been introduced. How can we choose from them in our actual development?
- From the design principle, the simple factory mode does not conform to the open and close principle.But it's amazing that in real life, the simple factory model does use the most.
- The factory method mode is designed to solve the creation of a single object, and its own mode is OK and complies with the open and close principle.But there is a problem with the expansion of the number of factory classes.It's a good choice if you don't have many factory classes to create.
- Abstract factory models are born to produce a family of products.So if you need to create a lot of objects, but there are distinct product family characteristics between them, then abstract factory mode is a good time to use.