This is the fourth day of my participation in the August More text Challenge. For details, see:August is more challenging

The factory pattern

  • Creation pattern:
    • Abstracting the instantiation process of a class separates the creation of an object from its use
      • In order to make the structure of the software more clear, the outside world only needs to know the common interface for the use of these objects, and does not care about the details of the implementation, which makes the whole system more consistent with the principle of single responsibility
      • The creation pattern hides the details of creating an instance of a class, making the entire system independent of each other by hiding the object creation and composition process
    • Creating patterns are more flexible about what is being created, by whom, and when
    • The factory pattern is an important creation pattern whose main function is to instantiate objects
  • Factory mode:Is responsible for instantiating classes that have a common interface
    • Mainly solve the interface selection problem
    • Used when different instances need to be created under different conditions
    • The factory pattern is a creation pattern that provides the best way to create objects
    • Creating an object using the factory pattern does not expose the creation logic to the client and uses a common interface to point to the newly created object
    • The factory pattern implements the factory interface in the subclass, and the creation process is performed in the subclass
  • Classification of factory patterns:
    • Simple Factory mode
    • Factory Method pattern
    • Abstract Factory pattern
  • Advantages of factory mode:
    • It can make the code structure clear and effectively encapsulate change
    • Block specific product classes for callers
    • Reduce the coupling of the code
  • Factory mode use scenarios:
    • The factory method pattern can be used anywhere complex objects need to be generated. Only complex objects are suitable for the factory method pattern. There is no need to use the factory pattern for simple objects that can be created with new. If you use the factory pattern for simple objects, you need to introduce a factory class to add complexity to the system
    • The factory pattern is a typical decoupling pattern that can be used to reduce coupling between systems when dependencies between classes need to be increased
    • The factory pattern is based on an abstract architecture, leaving the instantiation task to subclasses, and extensibility is good. When the system needs to be scalable, you can use the factory pattern, where different products use different factories for assembly

Simple factory mode

  • Simple Factory Pattern:
    • Define a class that is responsible for creating instances of the rest of the class, and return instances of different classes depending on the argument. The created instances usually have a common parent class
    • The methods used to create instances in the simple factory pattern are static static methods, so they are also called static factory method patterns
  • Simple factory mode roles:
    • Factory: The core class of the simple Factory pattern. Responsible for creating the internal logic for all products, the factory class can be called externally to create the required objects
    • Abstract Product class Product: The parent class of all objects created by the factory class, encapsulating the common methods of the Product. Improve the flexibility of the system. Make the factory class only need to define a generic factory method, because all concrete products created are this subclass object
    • ConcorrectProduct: All objects created are concrete instances of this class and need to implement the abstract methods declared in the abstract product

  • Simple factory pattern code implementation
  • Advantages of simple factory mode:
    • The simple factory pattern provides specialized classes for creating objects and achieves the separation of responsibilities. The Factory class contains the necessary logic to create an instance of the ConcreteProduct class. The client simply needs to consume the product
    • The client does not need to know the name of the ConcreteProduct class to be created. It only needs to know the parameters of the ConcreteProduct class
    • By introducing a configuration file, you can modify and add a new product class ConcreteProduct without modifying the client, increasing the flexibility of the system
  • Disadvantages of simple factory mode:
    • The Factory class aggregates the creation logic for all products, and if an exception occurs, the entire system will fail
    • The simple factory pattern increases the number of classes in the system, which increases the complexity and difficulty of understanding the system
    • In the simple factory mode, if new products need to be added, the factory logic needs to be modified, which violates the open closed principle and is not conducive to the expansion and maintenance of the system
    • The simple factory pattern uses a static approach and cannot form an inheritance-based hierarchical structure
  • Use scenarios for simple factory mode:
    • When there are fewer objects in the factory class responsible for creating
    • The client only needs to know the parameters of the factory class passed in, not the parameters of the created object

Simple factory class implementation

Pass the judgment parameter key directly

  • Factory:
public class Factory {
	public static Product produce(String concreteProductType) {
		switch (concreteProductType) {
			case "A" :
				return new ConcreteProductA();
				break;
			case "B" :
				return new ConcreteProductB();
				break;
			default :
				throw new Exception("There is no corresponding product type");
				break; }}}Copy the code
  • Question:
    • If you want to add a new product class, you need to add a case in the factory class
    • Contrary to the open closed principle, this method is not recommended

Using the reflection

  • Factory:
public Class Factory {
	public static Product produce(String concreteProductClassPathName) throw Exception {
		try {
			Product product = (Product)Class.forName(concreteProductClassPathName).newInstance();
			return product;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		throw new Exception("There is no equivalent product."); }}Copy the code
  • Question:
    • If you want to add a product class, you need to pass in the classpath name of the specific product class
    • You can optimize by configuring the classpath name of the specific product class in the Properties file and passing the classpath name into the method of the factory class by loading the configuration file
    • In this way, you only need to modify the configuration file to add a product class

Reflection is combined with configuration files

  • product.properties:
A=com.oxford.factory.simple.ConcreteProductA
B= com.oxford.factory.simple.ConcreteProductB
Copy the code
  • PropertyReader: Adds a configuration file read class to read configuration file information into the Map
public Class PropertyReader {
	public static Map<String, String> property = new HashMap<>();
	public Map<String, String> readProperty(String fileName) {
		Properties properties = new Properties();
		InputStream input = getClass.getResourceAsStream(fileName); 
		try {
			pro.load(input);
			Iterator<String> iterator = pro.StringPropertyNames().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				String value = properties.getProperty(key);
				map.put(key, value);
			}
			input.close();
		} catch (IOException e) {
			e.printStacTrace();
		}
		returnmap; }}Copy the code
  • Factory:
public Class Factory {
	public static Product produce(String concreteProductType) throws Exception {
		PropertyReader reader = new PropertyReder();
		Map<String, String> property = reader.readProperty("property.properties");
		try {
			Product product = (Product)Class.forName(property.get(concreteProductType)).newInstance();
			return product; 
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		throw new Exception("There is no equivalent product."); }}Copy the code
  • Question:
    • Each time a method is invoked, the configuration file has to be parsed, adding overhead
    • You can load the file read classes when the program starts, so you don’t have to parse the configuration file on each call

Summary of simple factory pattern

  • The factory class is the key to the whole simple factory pattern:
    • The factory class contains the necessary judgment logic to determine which specific product class to create based on the given parameters
    • By using factory classes, the client only needs to consume the specific product, rather than focus on the creation of the specific product object
    • By using the simple factory pattern to clarify the responsibilities of each class, the overall software architecture is optimized
  • The factory class centralizes the creation logic of all concrete objects, which violates the principle of responsibility allocation with high cohesion. In this way, classes created in the factory class can only be considered in advance, and if new classes need to be added, the logic of the factory class needs to be modified, which violates the open closed principle
  • As the number of specific product classes in the system increases, the need arises for the factory class to create different instances for different conditions. This kind of judgment of conditions and the judgment of specific product type are interlaced together, which is not conducive to the expansion and maintenance of the system. Such problems can be optimized by using the factory method pattern

Factory method pattern

  • Factory Method Pattern:
    • Define an interface for creating an object. The class that implements the interface determines which class to instantiate
    • The factory method pattern allows the instantiation of a concrete class to be deferred to subclasses
  • The role of the factory method pattern:
    • The factory classFactory:
      • Factory method interface, which typically returns an instance object of the abstract Product type Product
      • This class is at the heart of the factory method pattern and is independent of the client program. Any concrete product created in the pattern needs to implement this interface
    • Factory implementation classConcreteFactory:
      • Return an instance of the Abstract Product type, Product, of the ConcreteProduct class
      • The factory implementation class ConcreteFactory contains logic that is closely related to the client and is called by the client to create concrete instances of the product
    • Abstract product classProduct:
      • The parent class of the specific product class created by the factory method pattern, defining the methods common to the specific product of the class
    • Specific Product categoryConcreteProduct:
      • The concrete Product realization class, realizes the abstract Product class Product method
      • Every object created by the factory pattern is an instance of the ConcreteProduct class

  • Factory method pattern code implementation
  • Advantages of factory method mode:
    • In the factory method pattern, the product ConcreteProduct required by the client is created by the factory method. The user only needs to care about the factory implementation ConcreteFactory corresponding to the ConcreteProduct ConcreteProduct. You don’t need to care about the details of how the ConcreteProduct ConcreteProduct is created and the name of the ConcreteProduct class ConcreteProduct
    • The polymorphic design based on Factory class and abstract Product class is the key of Factory method pattern. In this way, the Factory class can determine what product ConcreteProduct object needs to be created, and the concrete implementation of creating the ConcreteProduct ConcreteProduct object is encapsulated inside the ConcreteFactory ConcreteFactory. The ConcreteFactory class ConcreteFactory has the same superclass interface Factory, so the Factory method pattern is also called the polymorphic Factory pattern
    • The factory method conforms to the open – closed principle and is beneficial to the expansion and maintenance of the system. To add a new product to the system, the factory method pattern simply adds a ConcreteFactory class ConcreteFactory and a ConcreteProduct class ConcreteProduct
  • Disadvantages of factory method mode:
    • In factory mode, when adding new products to the system, ConcreteProduct class ConcreteProduct and ConcreteFactory class ConcreteFactory need to be added. The number of classes in the system increases in pairs, which increases the system complexity and the overhead of system compilation and running to some extent
  • Use scenarios for the factory method pattern:
    • A class does not need to know the class of the desired object: in the factory method pattern, the client does not know the class name of the specific product class, only the specific factory implementation by which the specific product object was created. At this point, the client needs to know the concrete factory implementation class to create the concrete product
    • A class by subclasses to specify which create objects: the factory method pattern, only need one to create products in the factory class interfaces, founded by subclasses to determine specific to object, using polymorphism and the principle of substitution on the Richter scale, can run the program, covering the superclass object through a subclass object, so as to make the system has expanded
    • By delegating the creation of a specific product to a specific factory implementation of the factory class, the client does not need to care about the creation of a specific product class, but can dynamically specify the specific factory implementation of the product as needed. You can store the class name of a specific factory class in a configuration file or in a database
    • Example usage scenarios for the factory method pattern:
      • Logger: Logs can be recorded to local disks, system events, remote servers, and so on, and the user can choose where to log
      • Database access: When the user does not know which type of database the system will eventually use, and when the database may change
      • Server framework design: When designing a framework to connect to a server, three protocols may be used. POP3, IMAP, and HTTP can be thought of as product-specific classes, implemented using the factory method pattern

Factory method pattern summary

  • The factory method pattern is an abstraction and extension of the simple factory pattern. Through polymorphism, the factory method pattern keeps the advantages of the simple factory pattern and improves the disadvantages of the simple factory pattern
  • In the factory method pattern, the core factory class only provides the interface that must be implemented by the specific factory implementation, and is no longer responsible for the creation of specific products, which is completed by the specific factory implementation. This allows the system to extend the product-specific implementation without modifying the core factory classes
  • Advantages:
    • All the client needs to know to create the object is the specific factory implementation
    • The expansibility of the system is high. If new products are added, only a specific factory implementation class and a specific product class are needed, which conforms to the open-close principle
    • The specific implementation is hidden from the client, and the client only needs to care about the specific factory implementation
  • Disadvantages:
    • Each time a product is added, a concrete factory implementation class and a concrete product class need to be added, so that the number of classes in the system is multiplied, which increases the complexity of the system to a certain extent, and also increases the dependency of the system concrete classes. At the same time, the increase of classes also increases the system overhead during compilation and running

Abstract Factory pattern

  • Abstract Factory Pattern
    • Provides an interface or abstract class to create a set of related or interdependent concrete product objects without specifying a concrete class
  • The basic idea of the abstract factory pattern:
    • The factory method pattern solves the problem that the factory class has too much responsibility in the simple factory pattern by introducing the factory hierarchy. However, because each factory produces only one type of product in the factory method pattern, this can lead to a large number of factory class problems, which can increase the system overhead
    • Some related products can be grouped into a product family, produced by the same factory to unify
      • Product family: A family of functionally related products located in different product class structures
    • Abstract factory pattern differs from factory method pattern:
      • Abstract factory pattern:
        • The abstract factory pattern is a hierarchical structure for multiple products
        • Concrete product implementations of the abstract factory pattern either inherit from different interfaces or abstract classes
      • Factory method mode:
        • The factory method pattern is a hierarchical structure for a product
        • The concrete product implementation of the factory method pattern either inherits from the same interface or abstract class
  • The role of the abstract factory pattern:
    • AbstractFactory class AbstractFactory: the core of the AbstractFactory pattern, independent of the application’s business logic. Typically using an interface or abstract class, all ConcreteFactory classes must implement an interface or abstract class
    • ConcreteFactory class: Implements methods defined by the factory, including the business logic to create concrete product instances
    • AbstractProduct: an interface or abstract class that defines a class of product objects that is the parent class of objects created by the factory method pattern
    • ConcreteProduct: a ConcreteProduct that implements business logic. Each product object created in the abstract factory is an instance of a ConcreteProduct

  • Abstract factory pattern code implementation
  • Advantages of abstract factory pattern:
    • The abstract factory pattern separates the generation of concrete classes, and the client does not need to know about the concrete classes being created
    • When objects in a product family are designed to work together, clients are guaranteed to use only objects from the same product family
  • Abstract factory pattern disadvantages:
    • It is difficult to extend the product hierarchy if new product objects are added
  • Use scenarios for the abstract factory pattern:
    • Details of the creation, composition, and presentation of specific instances of a system that do not depend on product classes
    • There are multiple product families in the system, and only one of them is used at a time
    • Products from the same product family are used together
    • The system provides a library of product classes, the client does not depend on the implementation of a specific product, all products appear with the same interface
    • The system structure is stable and the product family will not be added frequently
  • Abstract Factory pattern problem:The inclination of the open – closed principle
    • The bias of the open closed principle in the abstract factory pattern is that it is convenient to add new products, but cumbersome to add new product families in the abstract factory pattern
    • The open closed principle requires that the system be closed for modification and open for extension. Functional enhancements for systems with multiple product families and multiple product hierarchies include:
      • Add products: To add new products, you only need to add a corresponding specific factory, no need to modify the existing code
      • Adding product family: To add a new product family to the product hierarchy, all factory roles, including the abstract factory class, need to be modified, and all factory classes need to add methods to produce the new product family products, which violates the open closed principle
    • Because the abstract factory pattern is inclined to open and close principle, it requires that all product families of the whole system should be considered at the beginning of the system design, and no new product families will be added after the completion of the design, nor will the existing product families be deleted. Otherwise, there will be a lot of changes to the system and it is difficult to maintain

Abstract Factory pattern summary

  • The abstract factory pattern is a further extension of the factory method pattern, providing more powerful factory classes for system extension
  • The abstract factory pattern separates the generation of concrete classes and makes it easy to switch concrete factories by exempting the client from knowledge of the product creation process. Because all concrete factories implement the public interface defined in the abstract factory, you can change the behavior of the entire system simply by changing the instance of the concrete factory
  • When multiple product objects in a product family work together, it is guaranteed that clients will always only use objects from the same product family
  • It is very convenient to add new products, no need to modify the existing system, in line with the open closed principle
  • However, it is very troublesome to increase the product hierarchy structure of the new product family of the system, which requires a lot of modifications to the original system, and even needs to modify the abstraction layer code, which violates the open closed principle