文章中如果有图看不到,可以点这里去 csdn 看看。从那边导过来的,文章太多,没法一篇篇修改好。

深入浅出设计模式【二、工厂方法模式】

一、工厂方法模式介绍

工厂方法模式,又称虚拟构造函数(Virtual Constructor)或多态性工厂(Polymorphic Factory),是一种非常经典且应用广泛的创建型设计模式

它的核心思想是将对象的实例化过程延迟到子类中进行。父类(工厂)定义了一个创建对象的接口,但由子类来决定要实例化的具体类是哪一个。这使得父类代码可以在不知道所要创建的具体类的情况下,与这些对象进行交互,从而实现了对扩展开放,对修改关闭的原则。

二、核心概念与意图

  1. 核心概念

    • 产品 (Product): 需要被创建的对象的抽象或接口。它是所有具体产品类需要实现的父类。
    • 具体产品 (Concrete Product): 实现产品接口的具体类,是工厂方法最终要创建的对象。
    • 创建者/工厂 (Creator): 声明工厂方法的类/接口。它通常包含一些依赖于产品的核心业务逻辑。
    • 具体创建者/具体工厂 (Concrete Creator): 重写或实现工厂方法,返回一个具体产品实例的类。
  2. 意图

    • 定义一个创建对象的接口,但让子类决定将哪一个类实例化
    • 使一个类的实例化延迟到其子类
    • 解耦客户端代码与具体类的依赖,客户端只依赖于产品的抽象接口和创建者的抽象接口,从而支持系统的扩展。

三、适用场景剖析

工厂方法模式在以下场景中非常有用:

  1. 无法预知对象确切类型及其依赖关系时: 当一个类无法预知它必须创建的对象的类,或者这个对象的创建依赖于外部配置、用户输入或运行时环境时。
  2. 希望提升系统的可扩展性时: 当你希望为库或框架的用户提供一种扩展其内部组件(即创建新“产品”)的方法时。框架定义接口和工厂方法,用户提供具体实现。
  3. 需要将对象创建代码集中管理时: 当对象创建过程复杂(如包含一系列步骤、需要配置等),希望将这部分代码与核心业务逻辑分离,提高代码的可维护性。
  4. 需要重用现有对象来节省资源时: 在某些场景下,工厂方法可以返回一个已存在的对象(例如来自对象池的对象),而不是总是创建一个新的实例。

四、类图解析

下图清晰地展示了工厂方法模式中各个角色之间的关系:

creates
creates
Creator
+someOperation()
+factoryMethod() : Product
ConcreteCreatorA
+factoryMethod() : Product
ConcreteCreatorB
+factoryMethod() : Product
«interface»
Product
+doSomething()
ConcreteProductA
+doSomething()
ConcreteProductB
+doSomething()
  • Creator: 声明工厂方法 (factoryMethod()),该方法返回一个 Product 类型的对象。Creator 也可以包含一些依赖于 Product 的核心业务逻辑 (someOperation())。
  • ConcreteCreatorAConcreteCreatorB: 重写 factoryMethod(),返回一个特定的 ConcreteProduct 实例。
  • Product: 定义产品对象的接口,所有具体产品都必须实现这个接口。
  • ConcreteProductAConcreteProductB: 实现 Product 接口的具体类。

调用流程: 客户端代码调用 ConcreteCreatorfactoryMethod(),该方法创建并返回一个 ConcreteProduct。客户端通过 Product 接口与返回的对象进行交互,因此它并不知道具体产品的确切类型。

五、各种实现方式及其优缺点

1. 经典实现(基于继承)

即上述UML所描述的方式,通过子类重写父类的抽象工厂方法来实现。

  • 优点
    • 符合开闭原则: 添加新的产品类型时,只需添加新的具体产品类和具体工厂类,无需修改现有代码。
    • 代码解耦: 客户端代码完全依赖于抽象(ProductCreator),不与任何具体类耦合。
  • 缺点
    • 类的数量爆炸性增长: 每增加一种产品,通常就需要增加一个具体产品类和一个具体工厂类,增加了系统的复杂度。

2. 参数化工厂方法

在工厂方法中传入一个参数(如字符串、枚举),根据参数的不同来创建不同的产品。

public abstract class Creator {
    public abstract Product factoryMethod(String type);

    public void someOperation() {
        Product p = factoryMethod("A"); // 通过参数指定类型
        p.doSomething();
    }
}

public class ConcreteCreator extends Creator {
    @Override
    public Product factoryMethod(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        }
        throw new IllegalArgumentException("Unknown product type.");
    }
}
  • 优点
    • 可以减少具体工厂类的数量。
  • 缺点
    • 违反了开闭原则。增加新产品时必须修改工厂方法内的逻辑(如添加新的 if-else 分支)。
    • 方法可能变得冗长复杂。

3. 使用反射或Lambda表达式(现代Java实现)

利用Java的反射机制或函数式接口进一步简化。

// 使用Supplier函数式接口作为“工厂”
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class LambdaFactory {
    private static final Map<String, Supplier<Product>> map = new HashMap<>();

    static {
        map.put("A", ConcreteProductA::new);
        map.put("B", ConcreteProductB::new);
    }

    public static Product createProduct(String type) {
        Supplier<Product> supplier = map.get(type);
        if (supplier != null) {
            return supplier.get();
        }
        throw new IllegalArgumentException("Unknown product type.");
    }
}
// 客户端调用:Product p = LambdaFactory.createProduct("A");
  • 优点
    • 非常灵活,易于扩展。注册新产品只需向Map中添加新的键值对。
    • 代码简洁
  • 缺点
    • 类型安全性稍差(基于字符串的Key)。
    • 反射可能带来性能开销(但通常可忽略不计)和安全性问题。

六、最佳实践

  1. 遵循依赖倒置原则 (DIP): 客户端应始终依赖于 ProductCreator 的抽象,而不是它们的实现。这是该模式的核心价值。
  2. 与简单工厂区分: 简单工厂(静态工厂方法)不是一个独立的设计模式,它虽然将创建逻辑封装了起来,但不具备工厂方法的“可扩展性”。如果需要扩展性(开闭原则),请使用标准的工厂方法模式
  3. 命名规范: 工厂方法的名字通常使用 createXXX(), makeXXX(), newInstance(), getXXX() 等,以提高代码的可读性。
  4. 考虑与模板方法模式结合Creator 类中的 someOperation() 方法通常是一个模板方法,它定义了操作的骨架,而将对象创建这一步骤延迟到子类(工厂方法)中实现。
  5. 避免过度设计: 如果对象创建过程非常简单,且不太可能变化,直接使用 new 是更简单明了的选择。不要为了使用模式而使用模式。

七、在开发中的演变和应用

工厂方法模式的思想在现代开发中得到了极大的演变和广泛应用:

  1. IoC容器和DI框架Spring框架的核心——IoC容器,就是一个超级工厂。它负责创建、组装和管理所有Bean对象的生命周期。应用上下文 (ApplicationContext) 就是 Creator,Bean定义是“产品规范”,而容器本身是负责实例化的“具体创建者”。这是工厂方法模式在架构层面的极致应用。
  2. 工具库中的静态工厂方法: Java标准库中的 Collections 类提供了如 Collections.unmodifiableList()Collections.singletonList() 等方法。这些是静态工厂方法,它们返回特定功能的具体列表实现,但客户端只依赖于 List 接口。
  3. ORM框架中的SessionFactory: 在Hibernate中,SessionFactory 是一个重量级的工厂,负责创建 Session 对象。每个 Session 可以看作是一个数据库连接/工作单元。SessionFactory 是线程安全的,而 Session 是非线程安全的。

八、真实开发案例(Java语言内部、知名开源框架、工具)

  1. Java集合框架 (Java Collections Framework)

    • java.util.Collections 类中的各种静态方法,如 synchronizedList(List list),返回一个同步的(线程安全的)列表包装器。这是一个参数化工厂方法的例子。
  2. Java XML处理 (JAXP)

    • javax.xml.parsers.DocumentBuilderFactory 是一个抽象类(Creator)。
    • 调用其静态方法 DocumentBuilderFactory.newInstance() 会根据系统属性或配置文件,加载一个具体的工厂实例(如Apache Xerces或Saxon的实现)。
    • 然后再通过具体工厂的 newDocumentBuilder() (工厂方法)来创建一个 DocumentBuilder (Product)。
  3. 日志框架 (Log4j 2 / SLF4J)

    • org.apache.logging.log4j.LoggerFactorygetLogger(String name) 方法。根据Logger的名称(通常是类名),返回一个特定的 Logger 实例。这背后使用了工厂方法来管理和复用Logger实例。
  4. Spring Framework

    • BeanFactory / ApplicationContext: 如前所述,是终极的工厂方法实现。getBean(String name) 是其核心的工厂方法。
    • FactoryBean接口: 这是一个特殊的接口。如果一个Bean实现了 FactoryBean,那么Spring容器获取到的不是这个Bean本身,而是它通过 getObject() (工厂方法)所返回的对象。这用于创建一些复杂的、无法直接通过默认构造函数创建的对象。

九、总结

方面总结
模式类型创建型设计模式
核心意图定义一个创建对象的接口,但让子类决定实例化哪个类。将实例化延迟到子类。
关键角色产品 (Product)、具体产品 (ConcreteProduct)、创建者 (Creator)、具体创建者 (ConcreteCreator)
主要优点1. 强大的解耦能力:将客户端与具体产品分离。
2. 符合开闭原则:易于扩展新的产品类型。
3. 符合单一职责原则:将创建逻辑集中管理。
4. 可读性更高:代码意图更明确。
主要缺点1. 可能引入类的泛滥:随着产品种类增加,具体工厂类会增多,系统复杂度增加。
2. 增加了抽象性:理解和管理层次结构需要更多精力。
适用场景1. 系统需要高扩展性,未来可能引入新产品。
2. 无法预知所要创建的对象的具体类型。
3. 希望将对象创建代码与使用代码解耦,集中管理创建逻辑。
关系与对比vs. 简单工厂: 简单工厂不具备工厂方法的“可扩展性”。
vs. 抽象工厂: 工厂方法创建一种产品,抽象工厂创建产品族。
vs. 模板方法: 工厂方法常是模板方法模式中的一个步骤。

工厂方法模式通过“延迟实例化到子类”这一巧妙的设计,极大地提高了系统的灵活性和可维护性,是框架设计中不可或缺的基石。理解并熟练运用它,是成为一名优秀架构师的必经之路。

posted @ 2025-08-29 12:56  NeoLshu  阅读(7)  评论(0)    收藏  举报  来源