工厂模式演进:从简单工厂到抽象工厂
以计算器为例,完整展示三种工厂模式的设计思路、实现差异和适用场景
演进逻辑
三种工厂模式是逐步改进的关系,每一种都解决了上一种模式的核心痛点,同时也引入了新的权衡。理解这种演进关系,是掌握工厂模式的关键:
- 简单工厂:最基础的封装,将对象创建与使用分离。核心问题:违反开闭原则。
- 工厂方法:将单一工厂拆分为多个工厂,完全解决开闭原则问题。新问题:类爆炸,只能生产单一产品。
- 抽象工厂:扩展工厂能力,支持生产一组相关产品(产品族)。新问题:新增产品等级困难。
一、简单工厂模式
1.1 模式详细介绍
定义:简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它定义一个工厂类,根据传入的参数动态决定创建哪一个产品类的实例。
核心思想:将对象的创建逻辑和对象的使用逻辑分离。客户端不需要知道对象是如何创建的,只需要向工厂传入一个参数,工厂就会返回对应的产品对象。
核心角色:
- 抽象产品(Operation):定义所有产品的公共接口
- 具体产品(AddOperation、SubOperation等):实现抽象产品接口的具体类
- 工厂类(OperationFactory):负责创建所有具体产品的实例
工作流程:
- 客户端向工厂类传入一个参数(如运算符"+")
- 工厂类根据参数判断需要创建哪个具体产品的实例
- 工厂类创建并返回该产品实例
- 客户端使用返回的产品实例完成业务逻辑
适用场景:产品数量较少且变化不频繁的场景;客户端只需要传入参数,不需要关心产品创建细节的场景。
1.2 计算器示例说明
我们以一个简单的计算器为例来演示简单工厂模式。计算器需要支持加、减、乘、除四种运算,每种运算都有相同的接口(接收两个数字,返回计算结果),但实现逻辑不同。
在简单工厂模式中,我们定义一个统一的Operation抽象类作为所有运算的父类,然后为每种运算创建一个具体的子类。最后创建一个OperationFactory工厂类,根据客户端传入的运算符("+"、"-"、"*"、"/")来创建对应的运算对象。
1.3 UML类图
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等):实现抽象工厂接口,创建对应的具体产品
工作流程:
- 客户端实例化对应的具体工厂(如AddFactory)
- 客户端调用工厂的createOperation()方法
- 具体工厂创建并返回对应的产品实例(如AddOperation)
- 客户端使用返回的产品实例完成业务逻辑
适用场景:单个产品等级,产品变化频繁的场景;需要符合开闭原则的场景;客户端不需要知道产品创建细节的场景。
2.2 计算器示例说明
在简单工厂模式的计算器例子中,当我们需要新增一种运算(如幂运算)时,必须修改OperationFactory类的代码,这违反了开闭原则。
为了解决这个问题,我们使用工厂方法模式对其进行改进。我们不再使用一个统一的工厂类来创建所有运算对象,而是为每种运算创建一个独立的工厂类。例如,AddFactory负责创建加法运算对象,SubFactory负责创建减法运算对象。所有这些工厂类都实现同一个IFactory抽象接口。
这样,当我们需要新增幂运算时,只需要新增PowerOperation产品类和PowerFactory工厂类即可,不需要修改任何原有代码。
2.3 UML类图(Mermaid 10.9.6 兼容版)
注: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等):实现抽象工厂接口,创建同一产品族下的所有产品
工作流程:
- 客户端实例化对应的具体工厂(如IntegerCalculatorFactory)
- 客户端调用工厂的多个方法,创建同一产品族下的多个产品
- 具体工厂创建并返回对应的产品实例
- 客户端使用这些产品实例完成业务逻辑
适用场景:存在多个产品等级,且产品族变化频繁的场景;需要保证同一产品族的产品一起使用的场景;系统需要独立于产品的创建和组合的场景。
3.2 计算器示例说明
在工厂方法模式的计算器例子中,每个工厂只能生产一种产品(运算对象)。但在实际应用中,我们经常需要创建一组相关的产品。
例如,我们的计算器现在需要支持两种模式:整数模式和浮点数模式。在整数模式下,不仅需要使用整数运算,还需要对输入进行整数验证;在浮点数模式下,需要使用浮点数运算,不需要特殊验证。
这里就存在两个产品等级:运算类和验证类;两个产品族:整数族(整数运算+整数验证)和浮点数族(浮点数运算+浮点数验证)。
使用抽象工厂模式,我们可以定义一个ICalculatorFactory抽象接口,包含创建运算对象和创建验证对象两个方法。然后为每个产品族创建一个具体工厂:IntegerCalculatorFactory负责创建整数运算和整数验证对象,DoubleCalculatorFactory负责创建浮点数运算和浮点数验证对象。
3.3 UML类图(Mermaid 10.9.6 兼容版)
注: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 优缺点分析(对比工厂方法)
✅ 改进的优点
- 支持生产产品族,保证同一族产品一起使用
- 新增产品族时符合开闭原则,只需新增工厂和产品类
- 隔离了具体产品的实现,客户端只依赖抽象接口
❌ 新的问题
- 新增产品等级困难:如新增减法运算,需要修改所有工厂类
- 结构最复杂,理解和实现难度最高
四、三种模式对比总结
| 模式 | 解决的问题 | 遗留的问题 | 适用场景 |
|---|---|---|---|
| 简单工厂 | 对象创建与使用分离 | 违反开闭原则 | 产品少、变化不频繁 |
| 工厂方法 | 解决开闭原则问题 | 类爆炸,只能生产单一产品 | 单个产品等级,变化频繁 |
| 抽象工厂 | 支持产品族创建 | 新增产品等级困难 | 多个产品等级,产品族变化频繁 |
五、使用建议
- 优先使用最简单的模式,不要为了设计而设计。如果产品数量少且稳定,简单工厂足够用。
- 当需要频繁新增产品时,升级到工厂方法模式,避免修改原有代码。
- 只有当存在明确的产品族概念,且需要保证产品之间的一致性时,才使用抽象工厂模式。
- 大多数实际项目中,工厂方法模式是最常用的,它在灵活性和复杂度之间取得了较好的平衡。