Creator pattern - factory pattern

Table of contents

1. Factory mode

1.1 Overview

1.2 Simple factory pattern

1.2.1 Structure

1.2.2 Implementation

1.2.3 Advantages and disadvantages

1.2.4 Static factory

1.3 Factory method pattern

1.3.1 Concept

1.3.2 Structure

1.3.3 Implementation

1.3.4 Advantages and disadvantages

1.4 Abstract factory pattern

1.4.1 Concept

1.4.2 Structure

1.4.3 Implementation

1.4.4 Advantages and disadvantages


1. Factory mode

1.1 Overview

Requirements: Design a coffee shop ordering system.

Design a coffee class (Coffee) and define its two subclasses (American Coffee [AmericanCoffee] and Latte Coffee [LatteCoffee]); design a coffee shop class (CoffeeStore), the coffee shop has the function of ordering coffee.

package zyy02;

public abstract class Coffee {
    public abstract String getName();
    public void addSugar(){
        System.out.println("加糖");
    }
    public void addMilk(){
        System.out.println("加奶");
    }

}
package zyy02;

public class AmericanCoffee extends Coffee{
    @Override
    public String getName() {
        return "美式咖啡";
    }
}
package zyy02;

public class LatteCoffee extends Coffee{
    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}
package zyy02;

public class CoffeeStore {
    public Coffee orderCoffee(String type){
        //声明coffee类型的变量,根据不同类型创建咖啡子类对象
        Coffee coffee=null;
        if("american".equals(type)){
            coffee=new AmericanCoffee();
        }else if("latte".equals(type)){
            coffee=new LatteCoffee();
        }else{
            throw new RuntimeException("对不起,你所点的咖啡没有");
        }
        //加配料
        coffee.addMilk();
        coffee.addSugar();

        return coffee;
    }
}
package zyy02;

public class Demo {
    public static void main(String[] args) {
        //创建咖啡点类
        CoffeeStore store=new CoffeeStore();
        //点咖啡
        Coffee coffee=store.orderCoffee("latte");
        System.out.println(coffee.getName());
    }
}

In java, everything is an object, and these objects need to be created. If you directly new the object when you create it, the object will be severely coupled. If we want to replace the object, all the places of the new object need to be modified, which obviously violates the The open-closed principle of software design . If we use the factory to produce objects, we can only deal with the factory and completely decouple from the object. If we want to replace the object, we can directly replace the object in the factory, achieving the purpose of decoupling from the object ; so , the biggest advantage of the factory pattern is: decoupling.

The use of three factories

  • Simple factory pattern (23 classic design patterns that do not belong to GOF)
  • factory method pattern
  • abstract factory pattern

1.2 Simple factory pattern

Simple factory is not a design pattern, but more like a programming habit

1.2.1 Structure

A simple factory contains the following roles:

  • Abstract product: defines the specification of the product and describes the main features and functions of the product.
  • Concrete products: implement or inherit subclasses of abstract products
  • Concrete factory: Provides a method to create a product, and the caller obtains the product through this method.

1.2.2 Implementation

 Now use a simple factory to improve the above case

  

package zyy02;

public abstract class Coffee {
    public abstract String getName();
    public void addSugar(){
        System.out.println("加糖");
    }
    public void addMilk(){
        System.out.println("加奶");
    }

}
package zyy02;

public class AmericanCoffee extends Coffee{
    @Override
    public String getName() {
        return "美式咖啡";
    }
}
package zyy02;

public class LatteCoffee extends Coffee{
    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}
package zyy02;

public class SimpleFactory {
    public Coffee createCoffee(String type){
        //声明coffee类型的变量,根据不同类型创建咖啡子类对象
        Coffee coffee=null;
        if("american".equals(type)){
            coffee=new AmericanCoffee();
        }else if("latte".equals(type)){
            coffee=new LatteCoffee();
        }else{
            throw new RuntimeException("对不起,你所点的咖啡没有");
        }
        return coffee;
    }
}
package zyy02;

public class CoffeeStore {
    public Coffee orderCoffee(String type){
        SimpleFactory factory=new SimpleFactory();
        //调用方法生产咖啡
        Coffee coffee=factory.createCoffee(type);
        //加配料
        coffee.addMilk();
        coffee.addSugar();

        return coffee;
    }
}
package zyy02;

public class Demo {
    public static void main(String[] args) {
        //创建咖啡点类
        CoffeeStore store=new CoffeeStore();
        //点咖啡
        Coffee coffee=store.orderCoffee("latte");
        System.out.println(coffee.getName());
    }
}

The factory handles the details of object creation. Once the SimpleCoffeeFactory exists, the orderCoffee() in the CoffeeStore class becomes the client of this object. If you need a Coffee object later, you can get it directly from the factory. In this way, the coupling with the Coffee implementation class is released, and new couplings are generated at the same time, the coupling between the CoffeeStore object and the SimpleCoffeeFactory factory object, and the coupling between the factory object and the commodity object.

If we add new types of coffee later, we will definitely need to modify the code of SimpleCoffeeFactory, which violates the principle of opening and closing. There may be many clients of the factory class, such as creating Meituan Waimai, etc. In this way, only the code of the factory class needs to be modified, and other modification operations are omitted.

1.2.3 Advantages and disadvantages

advantage:

The process of creating an object is encapsulated, and the object can be obtained directly through parameters. Separate the object creation from the business logic layer, so as to avoid modifying the customer code in the future. If you want to implement a new product, you can directly modify the factory class without modifying the original code, which reduces the possibility of customer code modification and is easier expand.

shortcoming:

When adding new products, it is still necessary to modify the code of the factory class, which violates the "open and close principle".

1.2.4 Static factory

In the development, some people also define the function of creating objects in the factory class as static. This is the static factory mode, which is not one of the 23 design modes. The difference from the above is that when calling the factory class, you can directly use the class name call:

public class SimpleCoffeeFactory {

    public static Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffe;
    }
}
package zyy02;

public class CoffeeStore {
    public Coffee orderCoffee(String type){
        //调用方法生产咖啡
        Coffee coffee=SimpleFactory.createCoffee(type);
        //加配料
        coffee.addMilk();
        coffee.addSugar();

        return coffee;
    }
}

1.3 Factory method pattern

For the shortcomings in the above example, using the factory method pattern can perfectly solve it, and fully follow the principle of opening and closing.

1.3.1 Concept

Define an interface for creating objects and let subclasses decide which product class object to instantiate. Factory methods defer instantiation of a product class to its factory subclasses.

1.3.2 Structure

The main role of the factory method pattern:

  • Abstract Factory (Abstract Factory): Provides an interface for creating products, and the caller uses it to access the factory method of the specific factory to create products.
  • Concrete Factory (ConcreteFactory): It mainly implements the abstract method in the abstract factory to complete the creation of specific products.
  • Abstract product (Product): defines the specification of the product and describes the main features and functions of the product.
  • Concrete Product (ConcreteProduct): implements the interface defined by the abstract product role, and is created by a specific factory, and it corresponds to a specific factory one-to-one.

1.3.3 Implementation

Improve the above example using the factory method pattern

 

public interface CoffeeFactory {

    Coffee createCoffee();
}
public class LatteCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}

public class AmericanCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}
public class CoffeeStore {

    private CoffeeFactory factory;

    public CoffeeStore(CoffeeFactory factory) {
        this.factory = factory;
    }

    public Coffee orderCoffee(String type) {
        Coffee coffee = factory.createCoffee();
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}

From the code written above, we can see that when adding product categories, factory categories should be added accordingly, and there is no need to modify the code of the factory category, which solves the shortcomings of the simple factory model. The factory method pattern is a further abstraction of the simple factory pattern. Due to the use of polymorphism, the factory method pattern maintains the advantages of the simple factory pattern and overcomes its shortcomings.

1.3.4 Advantages and disadvantages

advantage: 

  • Users only need to know the name of the specific factory to get the product they want, without knowing the specific creation process of the product;
  • When adding new products to the system, it is only necessary to add specific product categories and corresponding specific factory categories, without any modification to the original factory, and to meet the principle of opening and closing;

shortcoming:

  • Every time a product is added, a specific product category and a corresponding specific factory category must be added, which increases the complexity of the system.

1.4 Abstract factory pattern

1.4.1 Concept

The factory method model considers the production of one type of product, and the same type of product is called the same level of product, that is to say: the factory method model only considers the production of products of the same level

The abstract factory model to be introduced in this section will consider the production of multi-level products. A group of products at different levels produced by the same specific factory is called a product family, that is, products of the same brand. Products of the same brand are produced in same factory.

1.4.2 Structure

The main roles of the abstract factory pattern are as follows:

  • Abstract Factory (Abstract Factory): Provides an interface for creating products, which contains multiple methods for creating products, and can create multiple products of different levels.
  • Concrete Factory: It mainly implements multiple abstract methods in the abstract factory to complete the creation of specific products.
  • Abstract product (Product): defines the specification of the product, describes the main features and functions of the product, and the abstract factory pattern has multiple abstract products.
  • Concrete Product: implements the interface defined by the abstract product role, and is created by a specific factory. It has a many-to-one relationship with the specific factory.

1.4.3 Implementation

The current coffee shop business has changed, not only to produce coffee but also to produce desserts, such as tiramisu, matcha mousse, etc. If the factory method model is used, it is necessary to define tiramisu, matcha mousse, and tiramisu Factories, matcha mousse factories, and dessert factories are prone to explosions. Among them, latte coffee and American coffee are one product grade, both of which are coffee; tiramisu and matcha mousse are also one product grade; latte coffee and tiramisu are the same product family (that is, both belong to Italian style), Americano and matcha mousse are the same product family (that is, both belong to the American flavor). So this case can be implemented using the abstract factory pattern.

 

public interface DessertFactory {

    Coffee createCoffee();

    Dessert createDessert();
}
//美式甜点工厂
public class AmericanDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }

    public Dessert createDessert() {
        return new MatchaMousse();
    }
}
//意大利风味甜点工厂
public class ItalyDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }

    public Dessert createDessert() {
        return new Tiramisu();
    }
}

If you want to add the same product family, you only need to add a corresponding factory class, no need to modify other classes

1.4.4 Advantages and disadvantages

advantage:

When multiple objects in a product family are designed to work together, it guarantees that clients always use only objects from the same product family.

shortcoming:

When a new product needs to be added to the product family, all factory classes need to be modified.

Guess you like

Origin blog.csdn.net/qq_62799214/article/details/128695210