工厂方法(Factory Method)——类创建型模式

176 阅读4分钟

模式意图

提供一个创建对象的接口,由子类决定实例化哪个类,将类的实例化延迟到子类执行

模式结构

image.png

代码示例

abstract class Product {
    public void use() {}
}

class ConcreteProductA extends Product {
    public void use() {
        System.out.println("ConcreteProductA");
    }
}

class ConcreteProductB extends Product {
    public void use() {
        System.out.println("ConcreteProductB");
    }
}

abstract class Factory {
    public abstract Product createProduct();
}

class ConcreteFactoryA extends Factory {
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

public class Main {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactoryA();
        Product product = factory.createProduct();
        product.use();
    }
}

适用场景

  1. 一个类不知道它所需要的对象的类(在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道对应的工厂即可,具体的产品对象由工厂创建)
  2. 一个类通过子类来指定创建哪个对象,从而将创建产品的代码与实际使用的代码分离(在工厂方法模式中,抽象工厂只需要提供一个创建抽象产品的接口,工厂子类可以自己实现创建具体产品对象的过程)
  3. 将创建对象的任务委托给多个工厂子类中的一个,客户端在使用时可以无需关心是哪一个工厂子类,直接面向抽象的工厂父类编程(可以将具体子类放到配置文件动态加载)

常见案例

  1. JDBC连接数据库

模式效果(优缺点)

  1. 在工厂方法模式中,具体工厂用来创建具体的产品。客户在使用的时候,只需要关心产品所对应的具体工厂,无须关注产品是如何被实例化的,甚至不需要知道产品的类名
  2. 在系统中新增加产品时,无须修改抽象的工厂和抽象的产品提供的接口,只需要添加一个具体工厂以及具体工厂所创建出来的产品即可
  3. 在添加新产品时,需要编写具体的产品类,而且还需要提供对应的具体工厂,系统中的类将成对增加,在一定程度上增加了系统的复杂性
  4. 由于考虑系统的扩展性,需要引入抽象层,由于抽象层的存在,增加了系统的抽象性和理解难度

模式扩展

  1. 可以在工厂方法中添加参数来控制返回的产品类型,但是会导致程序中充斥 switch case
  2. 正如上述提到的,通过参数控制返回产品类型是具有缺点的。另一种方式是,在抽象工厂这个类中,可以定义多个工厂方法,从而使具体工厂角色实现这些不同的工厂方法,这些方法可以包含不同的业务逻辑,以满足对不同产品对象的需求,这样就离抽象工厂模式更近了一步
  3. 产品对象可以重复使用(工厂对象将已经创建的产品对象存储到一个集合中,然后根据用户的请求对集合进行查询,如果产品对象已经存在,则直接从集合中返回;否则新创建一个产品对象返回并且将其添加到集合中)
  4. 许多设计初期都会使用工厂方法模式,随后演化为使用抽象工厂原型或者生成器模式
  5. 抽象工厂通常基于一组工厂方法,但是你也可以使用原型模式来生成这些类的方法
  6. 原型模式并不基于继承,因此它不具有继承的缺点,但是原型模式需要被复制的对象有大量的初始化步骤;工厂方法基于继承,但是不需要初始化步骤
  7. 工厂方法模板方法的一个特殊形式(抽象工厂类中一般会包含默认的业务逻辑在抽象工厂方法中被调用,子类一般只需要重写实例化产品对象的方法即可)。同时,工厂方法可以作为大型模板方法中的一个步骤
  8. 可以同时使用工厂方法迭代器模式来让子类返回不同类型的迭代器,并使得迭代器与集合相匹配