工厂模式演进:从简单工厂到抽象工厂

以计算器为例,完整展示三种工厂模式的设计思路、实现差异和适用场景

演进逻辑

三种工厂模式是逐步改进的关系,每一种都解决了上一种模式的核心痛点,同时也引入了新的权衡。理解这种演进关系,是掌握工厂模式的关键:

  1. 简单工厂:最基础的封装,将对象创建与使用分离。核心问题:违反开闭原则
  2. 工厂方法:将单一工厂拆分为多个工厂,完全解决开闭原则问题新问题:类爆炸,只能生产单一产品
  3. 抽象工厂:扩展工厂能力,支持生产一组相关产品(产品族)新问题:新增产品等级困难

一、简单工厂模式

1.1 模式详细介绍

定义:简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它定义一个工厂类,根据传入的参数动态决定创建哪一个产品类的实例。

核心思想:将对象的创建逻辑和对象的使用逻辑分离。客户端不需要知道对象是如何创建的,只需要向工厂传入一个参数,工厂就会返回对应的产品对象。

核心角色:

  • 抽象产品(Operation):定义所有产品的公共接口
  • 具体产品(AddOperation、SubOperation等):实现抽象产品接口的具体类
  • 工厂类(OperationFactory):负责创建所有具体产品的实例

工作流程:

  1. 客户端向工厂类传入一个参数(如运算符"+")
  2. 工厂类根据参数判断需要创建哪个具体产品的实例
  3. 工厂类创建并返回该产品实例
  4. 客户端使用返回的产品实例完成业务逻辑

适用场景:产品数量较少且变化不频繁的场景;客户端只需要传入参数,不需要关心产品创建细节的场景。

1.2 计算器示例说明

我们以一个简单的计算器为例来演示简单工厂模式。计算器需要支持加、减、乘、除四种运算,每种运算都有相同的接口(接收两个数字,返回计算结果),但实现逻辑不同。

在简单工厂模式中,我们定义一个统一的Operation抽象类作为所有运算的父类,然后为每种运算创建一个具体的子类。最后创建一个OperationFactory工厂类,根据客户端传入的运算符("+"、"-"、"*"、"/")来创建对应的运算对象。

1.3 UML类图

classDiagram class Operation { +numberA float +numberB float +getResult() float } class AddOperation { +getResult() float } class SubOperation { +getResult() float } class MulOperation { +getResult() float } class DivOperation { +getResult() float } class OperationFactory { +createOperation(operator str) Operation } Operation <|-- AddOperation Operation <|-- SubOperation Operation <|-- MulOperation Operation <|-- DivOperation OperationFactory ..> Operation

1.4 Python代码实现

from abc import ABC, abstractmethod

# 抽象产品:运算基类
class Operation(ABC):
    def __init__(self):
        self.numberA: float = 0.0
        self.numberB: float = 0.0
    
    @abstractmethod
    def getResult(self) -> float:
        pass

# 具体产品:加法运算
class AddOperation(Operation):
    def getResult(self) -> float:
        return self.numberA + self.numberB

# 具体产品:减法运算
class SubOperation(Operation):
    def getResult(self) -> float:
        return self.numberA - self.numberB

# 具体产品:乘法运算
class MulOperation(Operation):
    def getResult(self) -> float:
        return self.numberA * self.numberB

# 具体产品:除法运算
class DivOperation(Operation):
    def getResult(self) -> float:
        if self.numberB == 0:
            raise ZeroDivisionError("除数不能为0")
        return self.numberA / self.numberB

# 简单工厂类
class OperationFactory:
    @staticmethod
    def createOperation(operator: str) -> Operation:
        match operator:
            case "+": return AddOperation()
            case "-": return SubOperation()
            case "*": return MulOperation()
            case "/": return DivOperation()
            case _: raise ValueError(f"不支持的运算符: {operator}")

# 客户端调用
if __name__ == "__main__":
    op = OperationFactory.createOperation("+")
    op.numberA = 10
    op.numberB = 5
    print(f"10 + 5 = {op.getResult()}")

1.5 优缺点分析

优点

  • 实现了对象创建与使用的分离
  • 客户端代码简单,只需传入运算符即可
  • 结构最简单,易于理解和实现

核心缺点

  • 违反开闭原则:新增运算必须修改工厂类代码
  • 工厂类职责过重,包含所有产品的创建逻辑

二、工厂方法模式

2.1 模式详细介绍

定义:工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

核心思想:将简单工厂中的单一工厂类拆分为抽象工厂接口和多个具体工厂类。每个具体工厂只负责创建一种对应的产品。这样,当新增产品时,只需要新增对应的产品类和工厂类,不需要修改原有代码,从而符合开闭原则。

核心角色:

  • 抽象产品(Operation):定义所有产品的公共接口
  • 具体产品(AddOperation、SubOperation等):实现抽象产品接口的具体类
  • 抽象工厂(IFactory):定义创建产品的接口
  • 具体工厂(AddFactory、SubFactory等):实现抽象工厂接口,创建对应的具体产品

工作流程:

  1. 客户端实例化对应的具体工厂(如AddFactory)
  2. 客户端调用工厂的createOperation()方法
  3. 具体工厂创建并返回对应的产品实例(如AddOperation)
  4. 客户端使用返回的产品实例完成业务逻辑

适用场景:单个产品等级,产品变化频繁的场景;需要符合开闭原则的场景;客户端不需要知道产品创建细节的场景。

2.2 计算器示例说明

在简单工厂模式的计算器例子中,当我们需要新增一种运算(如幂运算)时,必须修改OperationFactory类的代码,这违反了开闭原则。

为了解决这个问题,我们使用工厂方法模式对其进行改进。我们不再使用一个统一的工厂类来创建所有运算对象,而是为每种运算创建一个独立的工厂类。例如,AddFactory负责创建加法运算对象,SubFactory负责创建减法运算对象。所有这些工厂类都实现同一个IFactory抽象接口。

这样,当我们需要新增幂运算时,只需要新增PowerOperation产品类和PowerFactory工厂类即可,不需要修改任何原有代码。

2.3 UML类图(Mermaid 10.9.6 兼容版)

classDiagram class Operation { +numberA float +numberB float +getResult() float } class AddOperation { +getResult() float } class SubOperation { +getResult() float } class IFactory { +createOperation() Operation } class AddFactory { +createOperation() Operation } class SubFactory { +createOperation() Operation } Operation <|-- AddOperation Operation <|-- SubOperation IFactory <|-- AddFactory IFactory <|-- SubFactory IFactory ..> Operation

注:IFactory为抽象工厂接口,AddFactory、SubFactory为具体实现类

2.4 Python代码实现

from abc import ABC, abstractmethod

# 抽象产品:运算基类(与简单工厂完全相同)
class Operation(ABC):
    def __init__(self):
        self.numberA: float = 0.0
        self.numberB: float = 0.0
    
    @abstractmethod
    def getResult(self) -> float:
        pass

# 具体产品:加法运算(与简单工厂完全相同)
class AddOperation(Operation):
    def getResult(self) -> float:
        return self.numberA + self.numberB

# 具体产品:减法运算(与简单工厂完全相同)
class SubOperation(Operation):
    def getResult(self) -> float:
        return self.numberA - self.numberB

# 抽象工厂接口
class IFactory(ABC):
    @abstractmethod
    def createOperation(self) -> Operation:
        pass

# 具体工厂:加法工厂
class AddFactory(IFactory):
    def createOperation(self) -> Operation:
        return AddOperation()

# 具体工厂:减法工厂
class SubFactory(IFactory):
    def createOperation(self) -> Operation:
        return SubOperation()

# 客户端调用
if __name__ == "__main__":
    # 想要加法,就实例化加法工厂
    factory: IFactory = AddFactory()
    op = factory.createOperation()
    op.numberA = 10
    op.numberB = 5
    print(f"10 + 5 = {op.getResult()}")

2.5 优缺点分析(对比简单工厂)

改进的优点

  • 完全符合开闭原则:新增运算只需新增产品类和工厂类
  • 每个工厂职责单一,只负责创建一种产品
  • 降低了耦合度,一个工厂出错不会影响其他产品

新的问题

  • 类的数量成倍增加,造成类爆炸问题
  • 每个工厂只能生产单一产品
  • 无法处理一组相关产品需要一起创建的场景

三、抽象工厂模式

3.1 模式详细介绍

定义:抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。

核心思想:在工厂方法模式的基础上,扩展工厂接口,使其能够创建一组相关的产品(产品族)。一个具体工厂负责创建同一产品族下的所有产品,这样可以保证同一产品族的产品一起使用时的一致性。

核心概念:

  • 产品等级:同一类产品的不同实现(如加法运算、减法运算)
  • 产品族:不同产品等级中,属于同一主题的一组产品(如整数运算、整数验证)

核心角色:

  • 抽象产品(Operation、Validator):为每种产品定义公共接口
  • 具体产品(IntegerAddOperation、IntegerValidator等):实现抽象产品接口的具体类
  • 抽象工厂(ICalculatorFactory):定义创建一组产品的接口
  • 具体工厂(IntegerCalculatorFactory、DoubleCalculatorFactory等):实现抽象工厂接口,创建同一产品族下的所有产品

工作流程:

  1. 客户端实例化对应的具体工厂(如IntegerCalculatorFactory)
  2. 客户端调用工厂的多个方法,创建同一产品族下的多个产品
  3. 具体工厂创建并返回对应的产品实例
  4. 客户端使用这些产品实例完成业务逻辑

适用场景:存在多个产品等级,且产品族变化频繁的场景;需要保证同一产品族的产品一起使用的场景;系统需要独立于产品的创建和组合的场景。

3.2 计算器示例说明

在工厂方法模式的计算器例子中,每个工厂只能生产一种产品(运算对象)。但在实际应用中,我们经常需要创建一组相关的产品。

例如,我们的计算器现在需要支持两种模式:整数模式和浮点数模式。在整数模式下,不仅需要使用整数运算,还需要对输入进行整数验证;在浮点数模式下,需要使用浮点数运算,不需要特殊验证。

这里就存在两个产品等级:运算类和验证类;两个产品族:整数族(整数运算+整数验证)和浮点数族(浮点数运算+浮点数验证)。

使用抽象工厂模式,我们可以定义一个ICalculatorFactory抽象接口,包含创建运算对象和创建验证对象两个方法。然后为每个产品族创建一个具体工厂:IntegerCalculatorFactory负责创建整数运算和整数验证对象,DoubleCalculatorFactory负责创建浮点数运算和浮点数验证对象。

3.3 UML类图(Mermaid 10.9.6 兼容版)

classDiagram class Operation { +numberA float +numberB float +getResult() float } class IntegerAddOperation { +getResult() float } class DoubleAddOperation { +getResult() float } class Validator { +validate(a float, b float) bool } class IntegerValidator { +validate(a float, b float) bool } class DoubleValidator { +validate(a float, b float) bool } class ICalculatorFactory { +createOperation() Operation +createValidator() Validator } class IntegerCalculatorFactory { +createOperation() Operation +createValidator() Validator } class DoubleCalculatorFactory { +createOperation() Operation +createValidator() Validator } Operation <|-- IntegerAddOperation Operation <|-- DoubleAddOperation Validator <|-- IntegerValidator Validator <|-- DoubleValidator ICalculatorFactory <|-- IntegerCalculatorFactory ICalculatorFactory <|-- DoubleCalculatorFactory ICalculatorFactory ..> Operation ICalculatorFactory ..> Validator

注:Validator和ICalculatorFactory为抽象接口,其余为具体实现类

3.4 Python代码实现

from abc import ABC, abstractmethod

# 产品等级1:运算类
class Operation(ABC):
    def __init__(self):
        self.numberA: float = 0.0
        self.numberB: float = 0.0
    
    @abstractmethod
    def getResult(self) -> float:
        pass

# 具体产品:整数加法
class IntegerAddOperation(Operation):
    def getResult(self) -> float:
        return int(self.numberA) + int(self.numberB)

# 具体产品:浮点数加法
class DoubleAddOperation(Operation):
    def getResult(self) -> float:
        return self.numberA + self.numberB

# 产品等级2:验证类
class Validator(ABC):
    @abstractmethod
    def validate(self, a: float, b: float) -> bool:
        pass

# 具体产品:整数验证
class IntegerValidator(Validator):
    def validate(self, a: float, b: float) -> bool:
        return a.is_integer() and b.is_integer()

# 具体产品:浮点数验证
class DoubleValidator(Validator):
    def validate(self, a: float, b: float) -> bool:
        return True  # 浮点数无需特殊验证

# 抽象工厂接口(支持创建多个产品)
class ICalculatorFactory(ABC):
    @abstractmethod
    def createOperation(self) -> Operation:
        pass
    
    @abstractmethod
    def createValidator(self) -> Validator:
        pass

# 具体工厂:整数计算器工厂(生产整数族产品)
class IntegerCalculatorFactory(ICalculatorFactory):
    def createOperation(self) -> Operation:
        return IntegerAddOperation()
    
    def createValidator(self) -> Validator:
        return IntegerValidator()

# 具体工厂:浮点数计算器工厂(生产浮点数族产品)
class DoubleCalculatorFactory(ICalculatorFactory):
    def createOperation(self) -> Operation:
        return DoubleAddOperation()
    
    def createValidator(self) -> Validator:
        return DoubleValidator()

# 客户端调用
if __name__ == "__main__":
    # 切换工厂即可切换整个产品族
    factory: ICalculatorFactory = IntegerCalculatorFactory()
    op = factory.createOperation()
    validator = factory.createValidator()
    
    a = 10.0
    b = 5.0
    
    if validator.validate(a, b):
        op.numberA = a
        op.numberB = b
        print(f"整数加法结果: {op.getResult()}")
    else:
        print("输入不是整数,无法使用整数计算器")

3.5 优缺点分析(对比工厂方法)

改进的优点

  • 支持生产产品族,保证同一族产品一起使用
  • 新增产品族时符合开闭原则,只需新增工厂和产品类
  • 隔离了具体产品的实现,客户端只依赖抽象接口

新的问题

  • 新增产品等级困难:如新增减法运算,需要修改所有工厂类
  • 结构最复杂,理解和实现难度最高

四、三种模式对比总结

模式 解决的问题 遗留的问题 适用场景
简单工厂 对象创建与使用分离 违反开闭原则 产品少、变化不频繁
工厂方法 解决开闭原则问题 类爆炸,只能生产单一产品 单个产品等级,变化频繁
抽象工厂 支持产品族创建 新增产品等级困难 多个产品等级,产品族变化频繁

五、使用建议

  1. 优先使用最简单的模式,不要为了设计而设计。如果产品数量少且稳定,简单工厂足够用。
  2. 当需要频繁新增产品时,升级到工厂方法模式,避免修改原有代码。
  3. 只有当存在明确的产品族概念,且需要保证产品之间的一致性时,才使用抽象工厂模式。
  4. 大多数实际项目中,工厂方法模式是最常用的,它在灵活性和复杂度之间取得了较好的平衡。