Generally, the factory pattern is divided into three more subdivided types: simple factory, factory method and abstract factory. However, in GoF's book design patterns, it regards simple factory patterns as a special case of factory method patterns, so factory patterns are only divided into factory methods and abstract factories. In the rookie tutorial, the simple factory pattern is directly called factory pattern, which is divided into factory pattern (simple factory pattern) and abstract factory pattern. There is less talk about factory method pattern here.
In fact, these classifications are not so important. We can directly understand the three types of subdivision.
Simple factory mode
The simple factory pattern is one of the most commonly used design patterns in Java. It belongs to the creation pattern. In the factory method pattern, we will not expose the creation logic to the client when creating objects, and point to the newly created objects by using a common interface.
Simple factory pattern UML diagram:
It can be seen from this figure that the implementation of the simple factory mode is relatively simple. Directly refer to the code:
//This is an interface for creating objects (implemented) public interface Shape { void draw(); } //Here are two entity classes that implement interfaces public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } } public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } } //This is a factory class that generates an object of an entity class based on the given information. public class ShapeFactory { //Use the getShape method to get an object of shape type public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } } //The test class uses the factory to pass type information to obtain the object of the entity class. public class FactoryPatternDemo { public static void main(String[] args) { ShapeFactory shapeFactory = new ShapeFactory(); //Get the object of Rectangle and call its draw method Shape shape1 = shapeFactory.getShape("RECTANGLE"); //Call the draw method of Rectangle shape1.draw(); //Get the Square object and call its draw method Shape shape = shapeFactory.getShape("SQUARE"); //Call Square's draw method shape2.draw(); } }
The simple factory mode separates the generated product class code from the client (test) code. In the factory class, you can add the required logic code to generate the product, but the problem comes. Excellent java code conforms to the "open closed" principle, that is, for extension development and modification, if you want to add a product class 3, You need to modify the code that generates products in the factory class. Here you need to add if else judgment. For this problem, our factory method pattern can solve this problem.
Factory method model
Circle is added to the product category
public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } } //Unlike the simple factory pattern, the factory interface is declared here public interface Factory { //Declare the method that generates the product class public Product getShape(); } //Rectangle factory producing rectangle public class RectangleFactory implements Factory { //Implement the method of factory class to produce Rectangle public Shape getShape(){ return new Rectangle(); } } //SquareFactory that produces Square public class SquareFactory implements Factory { //Implement the method of factory class to produce Square public Shape getShape(){ return new Square(); } } //The CircleFactory that produces the Circle public class CircleFactory implements Factory { //Implement the method of factory class to produce Circle public Shape getShape(){ return new Circle (); } } //The test class obtains the object of the entity class by using its own factory. public class FactoryPatternDemo { public static void main(String[] args) { Factory factory; //Gets the object of the Rectangle factory = new RectangleFactory(); Shape shape1 = factory .getShape(); //Gets the object of Square factory = new SquareFactory(); Shape shape2 = factory .getShape(); //Gets the object of the Circle factory = new CircleFactory(); Shape shape3 = factory .getShape(); } }
UML diagram of factory method pattern: (an example is given)
In the factory method mode, we delay the generation of product classes by generating corresponding product classes through corresponding factory classes. Here, we can implement the "development closure" principle. No matter how many product classes are added, we do not need to modify the code in the original class, but by adding factory classes. But this still has disadvantages. If there are too many product classes, we have to generate a lot of factory classes. If we want to implement more than one product interface, that is, there are multiple product interfaces, and different product interfaces have corresponding product families. What is a product family? A simple understanding is that there will be sports car types, family types, commercial types, etc. in cars of different brands. Sports car types of cars of different brands can form a product family. In this case, we can adopt the abstract factory pattern.
Difference between simple factory mode and factory method mode:
The simple factory pattern is very similar to the factory method pattern.
The difference is: a simple factory has only three elements (entity class interface, entity class and factory class). It has no factory interface, and the method to get the product is generally static. Because there is no factory interface, the extensibility of the factory implementation is slightly weak, which can be regarded as a simplified version of the factory method pattern.
Abstract factory pattern
The abstract factory pattern is to create other factories around one super factory. The super factory can be understood as the factory of other factories.
UML diagram of abstract factory pattern:
I think the abstract factory pattern can be understood as the nesting of simple factory patterns. There is a simple factory pattern in the simple factory pattern. A factory is the generator of an entity class, and a factory has a factory generator.
//Shape interface public interface Shape { void draw(); } //Color interface public interface Color { void fill(); } //Here, the entity classes that implement these two interfaces are omitted //The abstract class of the factory, which is used to obtain the factory. public abstract class AbstractFactory { public abstract Color getColor(String color); public abstract Shape getShape(String shape) ; } //The factory class of AbstractFactory is extended to create the factory of shape entity class public class ShapeFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } @Override public Color getColor(String color) { return null; } } //The factory class of AbstractFactory is extended to create the factory of color entity class public class ColorFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ return null; } @Override public Color getColor(String color) { if(color == null){ return null; } if(color.equalsIgnoreCase("RED")){ return new Red(); } else if(color.equalsIgnoreCase("GREEN")){ return new Green(); } else if(color.equalsIgnoreCase("BLUE")){ return new Blue(); } return null; } } Create a factory generator class to get the factory by passing shape or color information. public class FactoryProducer { public static AbstractFactory getFactory(String choice){ if(choice.equalsIgnoreCase("SHAPE")){ return new ShapeFactory(); } else if(choice.equalsIgnoreCase("COLOR")){ return new ColorFactory(); } return null; } } //Test class, use FactoryProducer to obtain AbstractFactory, and obtain the object of entity class by passing type information. public class AbstractFactoryPatternDemo { public static void main(String[] args) { //Get shape factory AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE"); //Gets the object whose shape is Circle Shape shape1 = shapeFactory.getShape("CIRCLE"); //Call Circle's draw method shape1.draw(); //Gets an object with a rectangular shape Shape shape2 = shapeFactory.getShape("RECTANGLE"); //Call the draw method of Rectangle shape2.draw(); //Get color factory AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); //Gets an object with Red color Color color1 = colorFactory.getColor("RED"); //Call Red's fill method color1.fill(); //Gets the object with the color Green Color color2 = colorFactory.getColor("Green"); //Call Green's fill method color2.fill(); } }
In the abstract factory mode, we can define and implement more than one interface, and a factory can also generate more than one product class. The abstract factory mode better implements the "open closed" principle. It is a more abstract and general mode among the three modes. We should pay attention to the conditions for using the abstract factory pattern.
Simple factory and factory methods are commonly used, and abstract factory application scenarios are special, so they are rarely used.
Applicable scenarios of factory mode:
Whether it is simple factory pattern, factory method pattern or abstract factory pattern, they have similar characteristics, so their applicable scenarios are also similar.
First, as a creation class pattern, factory method pattern can be used wherever complex objects need to be generated. One thing to note is that complex objects are suitable for factory mode, while simple objects, especially objects that can be created only through new, do not need factory mode. If you use the factory pattern, you need to introduce a factory class, which will increase the complexity of the system.
Secondly, the factory model is a typical decoupling model, and the Dimitri rule (the least known principle, the less a class knows about other classes, the better) is particularly obvious in the factory model. If the caller needs to reduce dependencies when assembling products by himself, the factory mode can be considered. The coupling between objects will be greatly reduced.
Thirdly, because the factory pattern relies on abstract architecture, it assigns the task of instantiating products to the implementation class, which has good scalability. In other words, when the system needs better scalability, the factory mode can be considered, and different products can be assembled in different implementation factories.