GoF23:Factory-工厂

关键字 new:用于实例化一个具体的类。

缺点:在客户端直接使用 new 创建类,属于面向实现编程。

  1. 耦合度高:调用者必须知道所有可用的产品实现类,才可以根据需求获取实例。
  2. 可维护性差:当需求发生改变时,需要修改原有代码。

工厂(Factory)

处理创建对象的细节,实现创建者和调用者的分离

类型

  1. 简单工厂模式(静态工厂):编程习惯
  2. 工厂方法模式:对象的实例化延迟到子类。
  3. 抽象工厂模式:工厂的工厂。

1、简单工厂

1.1、定义

简单工厂(静态工厂)

是一种编程习惯,而不是真正意义上的设计模式。

  1. 做法
    1. 封装创建对象的代码,实现创建者和调用者的分离
    2. 通常将简单工厂中创建对象的方法声明为 static,aka 静态工厂。
  2. 特点
    1. 调用者只需传入正确参数即可获取所需产品对象,无需知道对象创建细节。
    2. 违反开闭原则:若需求改变(如增加或减少产品),需修改简单工厂的代码。

类图

image-20220107234359809

应用

  1. JDK 日期类:如 java.text.DateFormat

  2. Java 加密技术

    1. 获取不同加密算法的密钥生成器

    2. 创建密码器

      KeyGenerator keyGen = KeyGenerator.getInstance("DESede");
      Cipher cp = Cipher.getInstance("DESede");
      

1.2、示例

1.2.1、产品 - Pizza

抽象类:比萨

public abstract class Pizza {
    private String name;
    
    private Cheese cheese;
    private Clam clam;
    private Dough dough;
    private Pepperoni pepperoni;
    private Sauce sauce;
    private Veggies[] veggies;
    
    public void prepare() {...}
    public void bake() {...}
    public void cut() {...}
    public void box() {...}
}

子类:不同的比萨类型。

// 芝士
public class CheesePizza extends Pizza{
    ...
}

// 意大利辣香肠
public class PepperoniPizza extends Pizza{
    ...
}

1.2.2、客户端 - PizzaStore

基于不同 Pizza 类型,创建并做加工处理。

public class PizzaStore {
    private Pizza pizza();

    public Pizza orderPizza(String type) {
        // 创建产品
        switch (type) {
            case "cheese":
                pizza = new CheesePizza();
                break;
            case "pepperoni":
                pizza = new PepperoniPizza();
                break;
            default:
                pizza = null;
        }	

        // 处理产品
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

1.2.3、工厂 - PizzaFactory

orderPizza() 分析

该方法的核心功能是处理产品 Pizza,但代码中耦合了对产品的创建。

  1. 引入简单工厂,专门负责产品 Pizza 的创建。
  2. 需求变化只需修改简单工厂的逻辑,不会影响客户端代码。

代码示例

  1. 简单工厂

    public class PizzaFactory {
        public static Pizza createPizza(String type) {
            Pizza pizza;
    
            // 创建产品
            switch (type) {
                case "cheese":
                    pizza = new CheesePizza();
                    break;
                case "pepperoni":
                    pizza = new PepperoniPizza();
                    break;
                default:
                    pizza = null;
            }
            return pizza;
        }
    }
    
  2. 客户端:去掉创建产品的逻辑。

    public class PizzaStore {
        private Pizza pizza();
    
        public Pizza orderPizza(String type) {
            // 获取产品
            PizzaFactory.createPizza(type);
    
            // 处理产品
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
    
            return pizza;
        }
    }
    

2、工厂方法

2.1、定义

工厂方法

将对象的实例化推迟到子类,每个子类相当于一个工厂

  1. 做法:基于继承或实现。
    1. 定义一个创建对象的接口,由子类决定要实例化的类
    2. 通常工厂方法会根据不同入参创建不同的对象,aka 参数化工厂方法
  2. 说明
    1. 工厂方法创建的对象是同一个产品等级结构
    2. 针对参数化工厂方法,通常定义静态变量、枚举类来作为参数类型,以避免拼写错误。
    3. 遵守的设计原则:开闭、里氏替换、依赖倒置。

类图

image-20220107183541729

应用

示例:JDBC

Connection conn = DriverManager
    .getConnection("jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=DB;user=sa;password=");

Statement statement = conn.createStatement();

2.2、示例

2.2.1、PizzaStore

需求:PizzaStore 改为抽象类型,允许不同类型的子类(Pizza 加盟店)。

不同子类使用的产品 Pizza 不同。

public abstract class PizzaStore {
    ...
}

实现类:不同地区的 PizzaStore

  • 对于同一个 Pizza,芝加哥和纽约的风味可能不同。
  • 如 CheesePizza 类,单个类已无法满足需求,需要分为 ChicagoCheesePizza 和 NYCheesePizza。

2.2.2、工厂方法

PizzaStore 抽象类

定义创建产品 Pizza 的抽象方法,由子类(不同地区的 PizzaStore)实现其逻辑。

public abstract class PizzaStore {
    Pizza orderPizza(String type) {
        // 获取产品
        Pizza pizza = this.createPizza(type);

        // 处理产品
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

    // 工厂方法
    abstract Pizza createPizza(String type);
}

PizzaStore子类——即加盟店

  1. 实现类 1

    public class ChicagoPizzaStore extends PizzaStore{
        @Override
        Pizza createPizza(String type) {
            Pizza pizza;
    
            // 判断Pizza类型,获取Pizza
            switch (type) {
                case "cheese":
                    pizza = new ChicagoCheesePizza();
                    break;
                case "pepperoni":
                    pizza = new ChicagoPepperoniPizza();
                    break;
                default:
                    pizza = null;
            }
            return pizza;
        }
    }
    
  2. 实现类 2

    public class NyPizzaFactory extends PizzaSimpleFactory{
        @Override
        public Pizza createPizza(String type)  {
            Pizza pizza;
    
            // 判断Pizza类型,获取Pizza
            switch (type) {
                case "cheese":
                    pizza = new NYCheesePizza();
                    break;
                case "pepperoni":
                    pizza = new NYPepperoniPizza();
                    break;
                default:
                    pizza = null;
            }
            return pizza;
        }
    }
    

3、抽象工厂

3.1、定义

抽象工厂

  1. 做法:基于类的组合
    1. 定义一个创建工厂的接口,具体工厂用于创建相关或依赖的产品
    2. 通常使用工厂方法模式来实现具体工厂
  2. 说明
    1. 抽象工厂创建的对象是同一个产品族(多个相关的产品等级结构)。
    2. 开闭原则的倾斜性:抽象工厂模式存在以下场景,需要进行权衡。
      • 遵守开闭原则:对于产品族的扩展(即增加具体工厂),遵守。
      • 违反开闭原则:对于产品等级结构的扩展(即增加新的产品),违反。

类图

image-20220107235134252

3.2、对比

  1. 简单工厂
    1. 存在一个简单工厂类,负责所有具体产品的创建。
    2. 创建的对象是同一个产品类型
  2. 工厂方法
    1. 存在一个工厂方法接口 + 多个实现类,子类负责实例化。
    2. 基于继承/实现的方式创建对象。
    3. 创建的对象是同一个产品等级结构
  3. 抽象工厂
    1. 存在一个抽象工厂接口 + 多个工厂实现类
    2. 基于组合的方式创建对象。
    3. 创建的对象是同一个产品族(多个相关的产品等级结构)
posted @ 2021-12-16 14:34  Jaywee  阅读(69)  评论(0编辑  收藏  举报

👇