The application of various factory models

The application of various factory models

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 model is: decoupling .

1. Simple factory pattern (not 23 design patterns)

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

1.1 Structure

  • 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.

2.2 Implementation

2.2.1 Simple factory class diagram

The simple factory method handles the details of creating the object. Once it is available SimpleCoffeeFactory, the object CoffeeStore类in the middle orderCoffee()becomes the client of this object. If you need the Coffee object later, you can get it directly from the factory. In this way, the coupling with the Coffee implementation class is released , and at the same time , a new coupling between the CoffeeStore object and the SimpleCoffeeFactory factory object , and the coupling between the factory object and the commodity object are generated . In addition to new varieties of coffee , it is bound to need to modify SimpleCoffeeFactorythe code, which violates the principle of opening and closing . There may be many clients of the factory class. At this time, only the code of the factory class needs to be modified, and other modification operations are omitted.

insert image description here

2.2.2 Code

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 具体工厂:简单咖啡工厂类,用来生产咖啡
 */
public class SimpleCoffeeFactory {
    
    
    public Coffee createCoffee(String coffeeType){
    
    
        // 声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象
        Coffee coffee;
        if("american".equals(coffeeType)){
    
    
            coffee = new AmericanCoffee();
        }else if ("latte".equals(coffeeType)){
    
    
            coffee = new LatteCoffee();
        }else {
    
    
            throw new RuntimeException("sorry,本店没有出售此类咖啡");
        }
        return coffee;
    }
}

/**
 * Coffee店
 */
public class CoffeeStore {
    
    
    public Coffee orderCoffee(String coffeeType){
    
    
        // 创建简单工厂来提供生产咖啡的方法
        SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
        // 调用生产咖啡的方法
        Coffee coffee = factory.createCoffee(coffeeType);
        // 加配料
        coffee.addSugar();
        coffee.addMilk();
        return coffee;
    }
}

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

2.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".

2. Static factory pattern (not 23 design patterns)

Define the function of creating objects in the factory class as static, this is the static factory pattern, and it is not one of the 23 design patterns.

3.1 Code

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 具体工厂:简单咖啡工厂类,用来生产咖啡
 */
public class SimpleCoffeeFactory {
    
    
    // 静态方法
    public static Coffee createCoffee(String coffeeType){
    
    
        // 声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象
        Coffee coffee;
        if("american".equals(coffeeType)){
    
    
            coffee = new AmericanCoffee();
        }else if ("latte".equals(coffeeType)){
    
    
            coffee = new LatteCoffee();
        }else {
    
    
            throw new RuntimeException("sorry,本店没有出售此类咖啡");
        }
        return coffee;
    }
}

/**
 * Coffee店
 */
public class CoffeeStore {
    
    
    public Coffee orderCoffee(String coffeeType){
    
    
        // 不需要创建简单工厂来提供生产咖啡的方法
        // 直接类调用静态方法调用生产咖啡的方法
        Coffee coffee = SimpleCoffeeFactory.createCoffee(coffeeType);
        // 加配料
        coffee.addSugar();
        coffee.addMilk();
        return coffee;
    }
}

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

3. Factory mode

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 .

3.1 Structure

  • 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.

3.2 Implementation

3.2.1 Factory pattern class diagram

When adding product categories, factory categories should also 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.

insert image description here

3.2.2 Code

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 抽象工厂
 */
public interface CoffeeFactory {
    
    
    //创建咖啡对象的方法
    Coffee createCoffee();
}

/**
 * 美式咖啡工厂对象,专门用来生产美式咖啡
 */
public class AmericanCoffeeFactory implements CoffeeFactory {
    
    
    @Override
    public Coffee createCoffee() {
    
    
        return new AmericanCoffee();
    }
}

/**
 * 拿铁咖啡工厂,专门用来生产拿铁咖啡
 */
public class LatteCoffeeFactory implements CoffeeFactory{
    
    
    @Override
    public Coffee createCoffee() {
    
    
        return new LatteCoffee();
    }
}

/**
 * Coffee店
 */
public class CoffeeStore {
    
    
    private CoffeeFactory factory;
    public void setFactory(CoffeeFactory factory) {
    
    
        this.factory = factory;
    }
    //点咖啡功能
    public Coffee orderCoffee() {
    
    
        Coffee coffee = factory.createCoffee();
        //加配料
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}

/**
 * 客户点咖啡
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //创建咖啡店对象
        CoffeeStore store = new CoffeeStore();
        //创建对象
        //CoffeeFactory factory = new AmericanCoffeeFactory();
        CoffeeFactory factory = new LatteCoffeeFactory();
        store.setFactory(factory);
        //点咖啡
        Coffee coffee = store.orderCoffee();
        System.out.println(coffee.getName());
    }
}

3.2.3 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 .

4. Abstract factory pattern

The abstract factory pattern is an upgraded version of the factory method pattern. The factory method pattern only produces one level of products, while the abstract factory pattern can produce multiple levels of products . It is a pattern structure that provides an access class with an interface to create a group of related or interdependent objects, and the access class can obtain different levels of products of the same family without specifying the specific class of the desired product .

4.1 Structure

  • 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.

4.2 Implementation

4.2.1 Abstract Factory Pattern Class Diagram

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.

insert image description here

4.2.2 Code

If you want to add the same product family, you only need to add a corresponding factory class, and you don't need to modify other classes.

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 抽象产品:甜品
 */
public abstract class Dessert {
    
    
    public abstract void show();
}

/**
 * 具体产品:提拉米苏类
 */
public class Trimisu extends Dessert {
    
    
    public void show() {
    
    
        System.out.println("提拉米苏");
    }
}

/**
 * 具体产品:抹茶慕斯类
 */
public class MatchaMousse extends Dessert {
    
    
    public void show() {
    
    
        System.out.println("抹茶慕斯");
    }
}

/**
 * 抽象工厂: DessertFactory
 */
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 Trimisu();
    }
}

/**
 * 客户类
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //创建的是意大利风味甜品工厂对象
        //ItalyDessertFactory factory = new ItalyDessertFactory();
        //创建的是美式风味甜品工厂对象
        AmericanDessertFactory factory = new AmericanDessertFactory();
        //获取拿铁咖啡和提拉米苏甜品
        Coffee coffee = factory.createCoffee();
        Dessert dessert = factory.createDessert();
        System.out.println(coffee.getName());
        dessert.show();
    }
}

4.2.3 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.

4.2.4 Usage Scenarios

  • When the objects to be created are a series of interrelated or interdependent product families, such as TV sets, washing machines, and air conditioners in electrical appliances factories.

  • There are multiple product families in the system, but only one of them is used at a time. For example, someone only likes to wear clothes and shoes of a certain brand.

  • The product class library is provided in the system, and all products have the same interface, and the client does not depend on the creation details and internal structure of the product instance.

5. Mode extension

Decouple the factory object and the product object through the factory mode + configuration file . Load the full class name in the configuration file in the factory class, and create an object for storage. If the client needs the object, it can be obtained directly.

5.1 Define the configuration file

Define a configuration file named bean.properties.

american=config_factory.AmericanCoffee
latte=config_factory.LatteCoffee

5.2 Code

Static member variables are used to store created objects (the key stores the name, and the value stores the corresponding object), while reading configuration files and creating objects are written in static code blocks, so that they only need to be executed once.

/**
 * 抽象产品:咖啡
 */
public abstract class Coffee {
    
    
    // 抽象方法获取子类的咖啡的名称
    public abstract String getName();
    // 加糖
    public void addSugar() {
    
    
        System.out.println("加糖");
    }
    // 加奶
    public void addMilk() {
    
    
        System.out.println("加奶");
    }
}

/**
 * 具体产品:美式咖啡
 */
public class AmericanCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "美式咖啡";
    }
}

/**
 * 具体产品:拿铁咖啡
 */
public class LatteCoffee extends Coffee {
    
    
    // 继承父类的方法,重写直接返回名称
    public String getName() {
    
    
        return "拿铁咖啡";
    }
}

/**
 * 工厂类: CoffeeFactory
 * 加载配置文件,获取配置文件中配置的全类名,并创建该类的对象进行存储
 */
public class CoffeeFactory {
    
    
    // 定义容器对象存储咖啡对象
    private static HashMap<String,Coffee> map = new HashMap<String, Coffee>();
    // 加载配置文件, 只需要加载一次
    static {
    
    
        // 创建Properties对象
        Properties p = new Properties();
        // 调用p对象中的load方法进行配置文件的加载
        InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
    
    
            p.load(is);
            // 从p集合中获取全类名并创建对象
            Set<Object> keys = p.keySet();
            for (Object key : keys) {
    
    
                String className = p.getProperty((String) key);
                // 通过反射技术创建对象
                Class clazz = Class.forName(className);
                Coffee coffee = (Coffee) clazz.newInstance();
                // 将名称和对象存储到容器中
                map.put((String)key,coffee);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    // 根据名称获取对象
    public static Coffee createCoffee(String name) {
    
    
        return map.get(name);
    }
}

/**
 * 客户类
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        Coffee coffee = CoffeeFactory.createCoffee("american");
        System.out.println(coffee.getName());
    }
}

记录每一个学习瞬间

Guess you like

Origin blog.csdn.net/qq_51601665/article/details/131052702