Design Patterns - Factory Patterns - Scenarios and Advantages and Disadvantages

Remember one sentence:

The relationship between two classes A and B should only be that A creates B or A uses B, not both. 

 

During the teaching and promotion of design patterns, many corporate and school students often ask me what is the use of factory patterns (including simple factory patterns, factory method patterns and abstract factory patterns). Flexibility to create objects, and factories for Mao? Smile, in this article I will briefly talk about the role of factories around creating and using objects.

      There are usually three categories of responsibilities associated with an object: responsibilities that the object itself has, responsibilities that create objects, and responsibilities that use objects . The responsibility of the object itself is relatively easy to understand, that is, some data and behaviors of the object itself can be realized through some public methods. In this article, we will briefly discuss object creation responsibilities and usage responsibilities.

      In the Java language, we usually have the following ways to create objects:

       (1) Use the new keyword to create objects directly;

       (2) Create objects through reflection mechanisms;

       (3) Create an object through the clone() method;

       (4) Create objects through factory classes.

      There is no doubt that using the new keyword directly in the client code is the easiest way to create an object, but it is less flexible. Let's illustrate it with a simple example: 

[java]  view plain copy  
 
  1. class LoginAction {  
  2.     private UserDAO married;  
  3.       
  4.     public LoginAction() {  
  5.         udao =  new JDBCUserDAO();  //Create object  
  6.     }  
  7.       
  8.     public void execute() {  
  9.         //other code  
  10.         udao.findUserById();  //Use object  
  11.         //other code  
  12.     }  
  13. }  

      An object udao of type UserDAO is defined in the LoginAction class, a udao object of type JDBCUserDAO is created in the constructor of LoginAction, and the findUserById() method of the udao object is called in the execute() method. no problem. Let's analyze the relationship between LoginAction and UserDAO. The LoginAction class is responsible for creating an object of a UserDAO subclass and using UserDAO methods to complete the corresponding business processing. That is to say, LoginAction is responsible for both the creation of udao and the use of udao. , the responsibilities of creating objects and using objects are coupled together. This design will lead to a very serious problem: if you want to be able to use another subclass of UserDAO such as HibernateUserDAO type objects in LoginAction, you must modify the source code of the LoginAction class. Violates the "Open-Closed Principle". How to solve this problem?

      One of the most common solutions is to remove the udao object creation responsibility from the LoginAction class, and create the object outside the LoginAction class, so who is responsible for creating the UserDAO object? The answer is: the factory class. By introducing the factory class, the client class (such as LoginAction) does not involve the creation of the object, and the creator of the object does not involve the use of the object. The structure after the introduction of the factory class UserDAOFactory is shown in Figure 1:

Figure 1 Structure diagram after the introduction of the factory class

       The introduction of the factory class will reduce the maintenance workload due to changes in the product or factory class. If the constructor of a subclass of UserDAO changes or needs to add or remove different subclasses, just maintain the code of UserDAOFactory without affecting LoginAction; if the interface of UserDAO changes, such as adding, removing methods or Change the method name, only need to modify the LoginAction, will not bring any impact to UserDAOFactory.

       In all factory patterns, we emphasize one point: the relationship between two classes A and B should only be that A creates B or A uses B, not both. Separating the creation and use of objects also makes the system more in line with the "single responsibility principle", which is conducive to the reuse of functions and the maintenance of the system.

       Additionally, decoupling the creation and use of objects has the added benefit of preventing the data and code used to instantiate a class from being littered across multiple classes, allowing knowledge about creation to be moved into a factory class, as Joshua explained There is a dedicated section in Kerievsky's "Refactoring and Patterns" book. Because sometimes we create an object not only by simply calling its constructor, but also need to set some parameters, and may also need to configure the environment. If these codes are scattered in each client class that creates an object, code duplication and creation will inevitably occur. However, these client classes do not actually need to undertake the creation of objects, they only need to use the objects that have been created. At this point, a factory class can be introduced to encapsulate the object creation logic and the instantiation/configuration options of the client code.

      There is also a "not particularly obvious" advantage of using factory classes. A class may have multiple constructors. In languages ​​such as Java and C#, the names of the constructors are the same as the class name. The client can only pass in different parameters. To call different constructors to create objects, from the constructor and parameter list, you may not understand the difference between the products constructed by different constructors. But if the object creation process is encapsulated in a factory class, we can provide a series of factory methods with completely different names, each factory method corresponds to a constructor, and the client can create it in a more readable and understandable way object, and choosing a well-defined factory method from a set of factory methods is much more convenient than choosing a constructor from a set of constructors with the same name and different parameters. as shown in picture 2:

       In Figure 2, the rectangle factory class RectangleFactory provides two factory methods createRectangle() and createSquare(), one for creating rectangles and one for creating squares. These two methods are more efficient than creating rectangle or square objects directly through the constructor. The meaning is clearer, and to a certain extent, the probability of errors in client calls is reduced.

      So, one might ask, is it necessary to have a factory class for every class in the design? The answer is: a case-by-case analysis. If the product class is very simple, there are not too many variables, and the construction process is also very simple, there is no need to provide a factory class for it, and it can be instantiated directly before use, such as the String class in the Java language, we do not need to provide a factory class for it. It specifically provides a StringFactory, which is a bit like using a knife to kill a chicken. It is overkill, and it will lead to flooding of factories and increase the complexity of the system.

Reference: Creating objects and using objects - talk about the role of factories

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325154863&siteId=291194637