Simple factory, factory method, abstract factory, strategy pattern, difference between strategy and factory

 

Reprint: original address http://www.cnblogs.com/zhangchenliang/p/3700820.html

Simple factory, factory method, abstract factory, strategy pattern, difference between strategy and factory

Combine simple examples and UML diagrams to explain the simple principles of the factory pattern.

 

1. Introduction

It is said that ten years ago, there was an upstart who owned three cars (Benz (Benz), BMW (BMW), Audi (Audi)) and hired a driver to drive for him. However, the upstarts are always like this when they get in the car: after getting in the Benz, they say "Drive a Mercedes-Benz!";
You must say: This man is sick! Just say you can't drive? ! And when we put the behavior of this upstart into our programming language, we found that the C language has always used this way to ride the car!
Fortunately, this sickness is avoided in OO languages. The following is based on the Java language to introduce the theme of our article: the factory pattern!

2. Introduction

The factory pattern mainly provides an interface for creating objects. The factory pattern is divided into three categories according to the formulation in "Java and Patterns":
1. Simple Factory
2. Factory Method
3. Abstract Factory
These three patterns are from above The next step is abstract and more general. There is also a taxonomy, that is, the simple factory pattern is regarded as a special case of the factory method pattern, and the two are grouped together. Either, this is the classification method using "Java and Patterns".
Under what circumstances should we remember to use the factory pattern? There are basically two points:
1. It is not foreseeable at the time of coding what kind of instance of the class needs to be created.
2. The system should not depend on the details of how product class instances are created, combined and expressed.
What benefits can the factory pattern bring to our OOD and OOP? ?

3. Simple Factory Pattern

The pattern itself is very simple and is used in cases where the business is relatively simple. Generally used for small projects or when specific products are rarely extended (so that the factory class does not need to be changed frequently).
It consists of three roles:
Factory role: This is the core of this model, which contains certain business logic and judgment logic, and produces specific factory products according to different logics. Such as the Driver class in the example.
Abstract product role: It is generally a parent class inherited by a concrete product or an interface implemented. Implemented by an interface or abstract class. Such as the Car interface in the example.
Specific product role: The object created by the factory class is an instance of this role. It is implemented by a concrete class in java, such as the Benz and BMW classes in the example.


Let's use a class diagram to clearly represent the relationship between them:



 

 

Let's treat the nouveau riche: After using the simple factory model, now the nouveau riche just needs to sit in the car and say to the driver: "Drive". Let's see how it is implemented in code: (For convenience, all classes are placed in one file, so one class is declared as public)

//抽象产品  
abstract class Car{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
//具体产品  
class Benz extends Car{  
    public void drive(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
  
class Bmw extends Car{  
    public void drive(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
  
//简单工厂  
class Driver{  
    public static Car createCar(String car){  
        Car c = null;  
        if("Benz".equalsIgnoreCase(car))  
            c = new Benz();  
        else if("Bmw".equalsIgnoreCase(car))  
            c = new Bmw();  
        return c;  
    }  
}  
  
//老板  
public class BossSimplyFactory {  
  
    public static void main(String[] args) throws IOException {  
        //老板告诉司机我今天坐奔驰  
        Car car = Driver.createCar("benz");  
        car.setName("benz");  
         //司机开着奔驰出发  
        car.drive();  
    }  
<span style="font-family: courier new,courier;">}</span>  

If the boss wants to take an Audi, the same is true.

 

This is the simple factory pattern. So what benefits does it bring?
First, it fits the real world; and the client is relieved of the responsibility of directly creating the product object, and is only responsible for "consuming" the product (as the upstarts do).
Next, we will analyze the simple factory pattern from the principle of opening and closing. When the nouveau riche adds a car, as long as it conforms to the contract made by the abstract product, it can be used by the customer as long as the factory class is notified. (that is, create a new car class and inherit the abstract product Car) Then for the product part, it is in line with the open-closed principle - open for extension and closed for modification; but the factory class is not ideal, because each additional car For cars, it is necessary to add corresponding business logic and judgment logic to the factory class, which obviously violates the open-closed principle.

 

In practical applications, it is likely that the product is a multi-level tree structure. Since there is only one factory class for these products in the simple factory pattern, this might break our god class.
As I mentioned earlier, the simple factory pattern is suitable for cases where the business is simple or when specific products are rarely added. However, it may not be suitable for complex business environment. This should come from the factory method pattern! !

 

Fourth, the factory method pattern
Abstract factory role: This is the core of the factory method pattern, it has nothing to do with the application. It is an interface that a specific factory role must implement or a parent class that must be inherited. In java it is implemented by abstract classes or interfaces.
Specific factory role: It contains code related to specific business logic. Called by the application to create the corresponding product-specific object. In java it is implemented by concrete classes.
Abstract product role: It is the parent class that the concrete product inherits or the interface it implements. In java, there are generally abstract classes or interfaces to implement.
Specific Product Role: Objects created by a specific factory role are instances of this role. It is implemented by concrete classes in java.
Let's use a class diagram to clearly represent the relationship between them:

 

 

 

It is said that the upstart business is getting bigger and bigger, and their own cars are getting more and more. This is hard for the driver, he has to remember and maintain any car, and he has to use it! So the nouveau riche sympathized with him and said: I will assign you a few people, you just need to manage them well! So the management of the factory method pattern appeared. code show as below:

 

//抽象产品  
abstract class Car{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
//具体产品  
class Benz extends Car{  
    public void drive(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
class Bmw extends Car{  
    public void drive(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
  
  
//抽象工厂  
abstract class Driver{  
    public abstract Car createCar(String car) throws Exception;  
}  
//具体工厂(每个具体工厂负责一个具体产品)  
class BenzDriver extends Driver{  
    public Car createCar(String car) throws Exception {  
        return new Benz();  
    }  
}  
class BmwDriver extends Driver{  
    public Car createCar(String car) throws Exception {  
        return new Bmw();  
    }  
}  
  
//老板  
public class Boss{  
  
    public static void main(String[] args) throws Exception {  
        Driver d = new BenzDriver();  
        Car c = d.createCar("benz");   
        c.setName("benz");  
        c.drive();  
    }  
}

 

 Use the open-closed principle to analyze the factory method pattern. When a new product (that is, a car of a nouveau riche) is generated, it can be used by customers without modifying any existing code as long as it is generated according to the contract provided by the abstract product role and the abstract factory role. (That is, when there is a new product, just create and base the abstract product; create a new concrete factory to inherit the abstract factory; without modifying any class) The factory method pattern is completely in line with the open-closed principle!

 

Using the Factory Method pattern is sufficient for most of the business needs we might encounter. But when there are many types of products, there will be a large number of corresponding factory classes, which should not be what we want. So I suggest using the simple factory pattern combined with the factory method pattern to reduce factory classes in this case: that is, for similar types on the product tree (usually siblings in the leaves of the tree) use the simple factory pattern to accomplish.
Of course, special cases require special treatment: there are different product trees in the system, and there are product families on the product tree (the next section will explain this term). In this case, the abstract factory pattern may be used.

 

V. Summary

Let's take a look at the enlightenment of the simple factory pattern and the factory method pattern:
if we do not use the factory pattern to implement our example, maybe the code will be reduced a lot - just implement the existing car, do not use polymorphism. But in terms of maintainability, the extensibility is very poor (you can imagine the class that will be affected after adding a car). So in order to improve scalability and maintainability, it is worth writing more code.

 

 

6. Abstract Factory Pattern

Let's first understand what a product family is: A family of products located in different product hierarchy structures with related functions.

BmwCar and BenzCar in the figure are two product trees (product hierarchy); and BenzSportsCar and BmwSportsCar as shown in the figure are a product family. They all fit into the sports car family, so the functionality is relevant. Similarly, BmwBusinessCar and BenzBusinessCar are also a product family.
It can be said that the difference between it and the factory method pattern is the complexity of the objects that need to be created. And the abstract factory pattern is the most abstract and general of the three. The purpose of the abstract factory pattern is to provide an interface for the client to create product objects in multiple product families.
And the use of abstract factory pattern also needs to meet the following conditions:
1. There are multiple product families in the system, and the system can only consume one family of products at a time
. 2. Products belonging to the same product family are used.
Let's take a look at the various roles of the abstract factory pattern (same as the factory method):
The abstract factory role: This is the core of the factory method pattern, and it has nothing to do with the application. It is an interface that a specific factory role must implement or a parent class that must be inherited. In java it is implemented by abstract classes or interfaces.
Specific factory role: It contains code related to specific business logic. Called by the application to create the corresponding product-specific object. In java it is implemented by concrete classes.
Abstract product role: It is the parent class that the concrete product inherits or the interface it implements. In java, there are generally abstract classes or interfaces to implement.
Specific Product Role: Objects created by a specific factory role are instances of this role. It is implemented by concrete classes in java.



 

//抽象产品(Bmw和Audi同理)  
abstract class BenzCar{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
//具体产品(Bmw和Audi同理)  
class BenzSportCar extends BenzCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BenzSportCar-----------------------");  
    }  
}  
class BenzBusinessCar extends BenzCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BenzBusinessCar-----------------------");  
    }  
}  
  
abstract class BmwCar{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
class BmwSportCar extends BmwCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BmwSportCar-----------------------");  
    }  
}  
class BmwBusinessCar extends BmwCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BmwBusinessCar-----------------------");  
    }  
}  
  
abstract class AudiCar{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
class AudiSportCar extends AudiCar{  
    public void drive(){  
        System.out.println(this.getName()+"----AudiSportCar-----------------------");  
    }  
}  
class AudiBusinessCar extends AudiCar{  
    public void drive(){  
        System.out.println(this.getName()+"----AudiBusinessCar-----------------------");  
    }  
}  
  
  
//抽象工厂  
abstract class Driver3{  
    public abstract BenzCar createBenzCar(String car) throws Exception;  
      
    public abstract BmwCar createBmwCar(String car) throws Exception;  
      
    public abstract AudiCar createAudiCar(String car) throws Exception;  
}  
//具体工厂  
class SportDriver extends Driver3{  
    public BenzCar createBenzCar(String car) throws Exception {  
        return new BenzSportCar();  
    }  
    public BmwCar createBmwCar(String car) throws Exception {  
        return new BmwSportCar();  
    }  
    public AudiCar createAudiCar(String car) throws Exception {  
        return new AudiSportCar();  
    }  
}  
class BusinessDriver extends Driver3{  
    public BenzCar createBenzCar(String car) throws Exception {  
        return new BenzBusinessCar();  
    }  
    public BmwCar createBmwCar(String car) throws Exception {  
        return new BmwBusinessCar();  
    }  
    public AudiCar createAudiCar(String car) throws Exception {  
        return new AudiBusinessCar();  
    }  
}  
  
//老板  
public class BossAbstractFactory {  
  
    public static void main(String[] args) throws Exception {  
          
        Driver3 d = new BusinessDriver();  
        AudiCar car = d.createAudiCar("");  
        car.drive();  
    }  
}

 

Among them: BenzSportCar and BenzBusinessCar belong to the product tree; similarly BmwSportCar and BmwBusinessCar. The BenzSportCar and BMWSportCar and AudiSportCar belong to the product family.

Therefore, the abstract factory pattern is generally used in scenarios with product trees and product families.

Disadvantages of the abstract factory pattern: If you need to add a new product tree, then you need to add three product classes, such as VolvoCar, VolvoSportCar, VolvoSportCar, and modify the three factory classes. Such a large batch of changes is ugly.

So you can use a simple factory with reflection to improve the abstract factory:
UML diagram omitted.

abstract class BenzCar{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
class BenzSportCar extends BenzCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BenzSportCar-----------------------");  
    }  
}  
class BenzBusinessCar extends BenzCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BenzBusinessCar-----------------------");  
    }  
}  
  
abstract class BmwCar{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
class BmwSportCar extends BmwCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BmwSportCar-----------------------");  
    }  
}  
class BmwBusinessCar extends BmwCar{  
    public void drive(){  
        System.out.println(this.getName()+"----BmwBusinessCar-----------------------");  
    }  
}  
  
abstract class AudiCar{  
    private String name;  
      
    public abstract void drive();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
class AudiSportCar extends AudiCar{  
    public void drive(){  
        System.out.println(this.getName()+"----AudiSportCar-----------------------");  
    }  
}  
class AudiBusinessCar extends AudiCar{  
    public void drive(){  
        System.out.println(this.getName()+"----AudiBusinessCar-----------------------");  
    }  
}  
  
  
/** 
 * 简单工厂通过反射改进抽象工厂及其子工厂 
 * @author Administrator 
 * 
 */  
class Driver3{  
    public static BenzCar createBenzCar(String car) throws Exception {  
        return (BenzCar) Class.forName(car).newInstance();  
    }  
      
    public static BmwCar createBmwCar(String car) throws Exception {  
        return (BmwCar) Class.forName(car).newInstance();  
    }  
      
    public static AudiCar createAudiCar(String car) throws Exception {  
        return (AudiCar) Class.forName(car).newInstance();  
    }  
}  
//客户端  
public class SimpleAndAbstractFactory {  
  
    public static void main(String[] args) throws Exception {  
  
        AudiCar car = Driver3.createAudiCar("com.java.pattendesign.factory.AudiSportCar");  
        car.drive();  
    }  
}  

 

strategy mode

 From the perspective of strategy, the strategy mode is a mode that tends to be behavioral . It is somewhat similar to the battle plan when looking for a battle. Generally, the commander will make several different plans according to the actual situation before the battle. If the situation at that time has changes, it will be determined according to the corresponding conditions which set of plans to replace the original plan. But no matter how many times it is replaced, the battle will still be fought.

  For example: the function of exporting to EXCEL, WORD, and PDF files. Although the specific operations of these three types of export are slightly different, most of them are the same.


The strategy pattern and the factory pattern are basically the same from the uml diagram. It's just that the emphasis on encapsulation is different. We explain the strategy pattern by comparing the factory pattern and the strategy pattern.

We can understand the factory model as follows: Suppose an Audi company produces cars, and it masters a core technology of producing cars. On the other hand, the cars it produces have different models and are assembled on different production lines. After the customer makes a reservation through the sales department, Audi will produce the car it needs for the customer on the designated production line.

The strategy pattern is similar in structure to the factory pattern. The only difference is that the operation of instantiating a product in the factory pattern is done on the server side. The identity instantiates an object. The client of the strategy mode conveys an instance to the server, and the server just takes the instance and executes the method of the instance in the environment of the server. It's like a person who doesn't know much about cars goes to buy a car. He makes a gesture there and says what he wants. The sales department forms an order according to his "signature". This is the work in the factory mode. Way. In the strategy mode, the customer is an expert. He himself gave the detailed information of the order, and the sales department just turned it over and handed it over to the production department to do it. By comparing the two, it is not difficult to find that the factory model must provide a sufficiently flexible sales department. If the user has new needs, the sales department must immediately realize it so that appropriate orders can be made. Therefore, if a new car comes out, both the production department and the sales department need to be updated, and the description of the new car needs to be updated for customers, so there are three places that need to be changed. The sales department in the strategy mode is relatively fixed, it is only responsible for accepting orders and performing a few specific operations. When a new car comes out, it is only necessary to update the codes of the production department and the client on the server side, without updating the codes of the sales department. 

Technical Support: Simple factories and strategies are based on object-oriented encapsulation and polymorphism. The idea of ​​their implementation is to set an abstract model and derive various methods that meet the needs of different customers from the model, and then encapsulate them.

The difference between the factory mode and the strategy mode is that the location of instantiating an object is different. For the factory mode, the instantiated object is placed on the server side, that is, it is placed in the factory class;

The operation of instantiating an object in the strategy mode is on the client side, and the "sales department" on the server side is only responsible for passing the object and performing specific operations in the server side environment. . .

The factory mode requires the sales department of the server to be sensitive enough, and the strategy mode encapsulates the strategy, so his sales department is stupid, and the customer needs to provide enough parameters to distinguish which strategy to use, and the best is the strategy. instance.

//抽象产品  
abstract class AudiCar{  
    private String name;  
      
    public abstract void makeCar();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
//具体产品  
class AudiA6 extends AudiCar{  
    public void makeCar(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
class AudiA4 extends AudiCar{  
    public void makeCar(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
  
//销售部门----服务端  
class CarContext {  
    AudiCar audiCar = null;  
  
    public CarContext(AudiCar audiCar) {  
        this.audiCar = audiCar;  
    }  
      
    public void orderCar(){  
        this.audiCar.makeCar();  
    }  
}  
  
//客户----客户端(这个客户是内行,什么都懂,他说我要A6,销售部门立刻给他a6,所以销售部门不用很懂)  
public class SimplyFactoryAndStrategy2 {  
  
    public static void main(String[] args) throws IOException {  
          
        //客户说我要什么什么样子的车子,销售人员才知道他要什么样子的车子  
        AudiCar car = new AudiA6();  
        car.setName("a6");  
          
        CarContext context = new CarContext(car);  
        context.orderCar();  
    }  
}  
  
  
//工厂模式---与上面的策略模式比较  
//抽象产品  
abstract class AudiCar{  
    private String name;  
      
    public abstract void makeCar();  
      
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
//具体产品  
class AudiA6 extends AudiCar{  
    public void makeCar(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
class AudiA4 extends AudiCar{  
    public void makeCar(){  
        System.out.println(this.getName()+"----go-----------------------");  
    }  
}  
  
//简单工厂---销售部门----服务端  
class CarFactroy{  
    public static AudiCar createCar(String car){  
        AudiCar c = null;  
        if("A6".equalsIgnoreCase(car))  
            c = new AudiA6();  
        else if("A4".equalsIgnoreCase(car))  
            c = new AudiA4();  
        return c;  
    }  
}  
  
//客户----客户端(这个客户是外行,什么都不懂,只要随便描述下车,销售部门才能知道他要那款车,所以销售部门比较牛)  
public class SimplyFactoryAndStrategy {  
  
    public static void main(String[] args) throws IOException {  
          
        System.out.print("请输入您要坐的车:(A6、A4)");  
        String carName = new BufferedReader(new InputStreamReader(System.in)).readLine();  
          
        //客户说我要什么什么样子的车子,销售人员才知道他要什么样子的车子  
        AudiCar car = CarFactroy.createCar(carName);  
        car.setName(carName);  
        car.makeCar();    
    }  
}

 

Advantages and disadvantages of the strategy pattern

  The main advantages of the strategy pattern are:

  • The strategy classes can be switched freely. Since the strategy classes are implemented from the same abstraction, they can be switched freely.
  • Easy to extend, adding a new strategy is very easy for the strategy pattern, basically it can be extended without changing the original code.
  • Avoid using multiple conditions. If you do not use the strategy mode, you must use conditional statements to connect all algorithms, and decide which algorithm to use through conditional judgment. As we have mentioned in the previous article, using multiple conditional judgments is Very difficult to maintain.

  There are two main disadvantages of the strategy pattern:

  • Maintaining each strategy class will bring additional overhead to development, and everyone may have experience in this area: Generally speaking, if the number of strategy classes exceeds 5, it will be a headache.
  • All strategy classes must be exposed to the client (caller), because which strategy to use is determined by the client, therefore, the client should know what strategy is available and understand the difference between various strategies, otherwise, the consequences Very serious. For example, there is a strategy mode for sorting algorithms, which provides three algorithms: quick sort, bubble sort, and selection sort. Before using these algorithms, does the client need to understand the applicability of these three algorithms? For another example, the client needs to use a container, which is implemented by a linked list and an array. Does the client also need to understand the difference between a linked list and an array? This is against the Law of Demeter.

Applicable scene

        Those who do object-oriented design must be very familiar with the strategy pattern, because it is essentially the inheritance and polymorphism in object-oriented design. After reading the general code of the strategy pattern, I think, even if I have never heard of the strategy pattern before, Must have used it during development too, right? At least in the following two cases, you can consider using the strategy pattern,

  • The main logic of several classes is the same, and only some of the logic algorithms and behaviors are slightly different.
  • There are several similar behaviors, or algorithms, and the client needs to dynamically decide which one to use, so the strategy pattern can be used to encapsulate these algorithms for the client to call.

       The strategy pattern is a simple and commonly used pattern. When we develop it, we often use it intentionally or unintentionally. Generally speaking, the strategy pattern is not used alone, but is often used in combination with the template method pattern and factory pattern. .

 

 

Large-grained if --else if... can be done using the factory + strategy pattern.

Guess you like

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