概念:
工厂模式属于创建型设计模式,核心思想是将对象的创建过程封装到工厂类中,客户端无需关心具体对象的创建细节,实现创建与使用的解耦。
模式分类
-
简单工厂模式(静态工厂)
-
工厂方法模式(多态工厂)
-
抽象工厂模式(产品族工厂)
工厂模式的核心优势
1. 解耦创建与使用
- 客户端代码无需依赖具体类,只需要与抽象接口交互
- 符合依赖倒置原则(DIP)
2. 可扩展性强
- 新增产品时,只需添加新的具体工厂和产品类
- 符合开闭原则(对扩展开放,对修改关闭)
3. 统一创建逻辑
- 将复杂的对象初始化过程封装在工厂中
- 避免代码重复(例如:参数验证、资源分配)
简单工厂模式,抽象公共接口,然后封装不同类型,最后创建一个工厂(类比名)统一处理这些封装对象,然后在实现的时候根据传递的参数实例化不同的对象。
python
# 步骤1:定义产品接口
class Car:
def drive(self):
pass
# 步骤2:创建具体产品
class Tesla(Car):
def drive(self):
print("特斯拉电动车启动...")
class BMW(Car):
def drive(self):
print("宝马燃油车启动...")
# 步骤3:创建工厂
class CarFactory:
@staticmethod
def create_car(brand):
if brand == "tesla":
return Tesla()
elif brand == "bmw":
return BMW()
else:
raise ValueError("不支持的车型")
# 使用示例
if __name__ == "__main__":
# 通过工厂创建对象
car1 = CarFactory.create_car("tesla")
car2 = CarFactory.create_car("bmw")
car1.drive() # 输出:特斯拉电动车启动...
car2.drive() # 输出:宝马燃油车启动...
代码结构解析:
Car
是产品基类(接口)Tesla
和BMW
是具体产品CarFactory
是工厂类,根据参数创建不同产品- 使用者只需要和工厂交互,不需要知道具体类的创建细节
工厂模式的核心优势:将对象的创建和使用解耦,当需要新增产品时,只需要扩展工厂类,不需要修改已有代码。
下面以工厂方法模式为例进行完整实现,把产品和工厂都进行抽象,在最后调用的时候不需要实例化最上层的接口:
Python 代码实现
1. 定义抽象产品接口
python
from abc import ABC, abstractmethod
# 抽象产品:车辆接口
class Vehicle(ABC):
@abstractmethod
def start_engine(self):
pass
@abstractmethod
def stop_engine(self):
pass
2. 实现具体产品类
python
# 具体产品:电动车
class ElectricCar(Vehicle):
def start_engine(self):
print("⚡️ 电动车电机启动(无声)")
def stop_engine(self):
print("⚡️ 电动车电机关闭")
# 具体产品:燃油车
class GasolineCar(Vehicle):
def start_engine(self):
print("🔥 燃油车发动机启动(轰鸣声)")
def stop_engine(self):
print("🔥 燃油车发动机关闭")
3. 定义抽象工厂接口
python
# 抽象工厂
class VehicleFactory(ABC):
@abstractmethod
def create_vehicle(self) -> Vehicle:
pass
4. 实现具体工厂类
python
# 具体工厂:电动车工厂
class ElectricCarFactory(VehicleFactory):
def create_vehicle(self) -> Vehicle:
print("制造电动车:安装电池组、电机...")
return ElectricCar()
# 具体工厂:燃油车工厂
class GasolineCarFactory(VehicleFactory):
def create_vehicle(self) -> Vehicle:
print("制造燃油车:安装发动机、油箱...")
return GasolineCar()
5. 客户端使用示例
python
def client_code(factory: VehicleFactory):
# 客户端无需知道具体产品类型
vehicle = factory.create_vehicle()
vehicle.start_engine()
vehicle.stop_engine()
print("-" * 40)
if __name__ == "__main__":
# 选择电动车工厂
electric_factory = ElectricCarFactory()
client_code(electric_factory)
# 选择燃油车工厂
gasoline_factory = GasolineCarFactory()
client_code(gasoline_factory)
输出结果
python
制造电动车:安装电池组、电机...
⚡️ 电动车电机启动(无声)
⚡️ 电动车电机关闭
----------------------------------------
制造燃油车:安装发动机、油箱...
🔥 燃油车发动机启动(轰鸣声)
🔥 燃油车发动机关闭
----------------------------------------
适用场景
- 需要创建多种类型对象,且这些对象有共同接口
- 创建过程涉及复杂初始化逻辑
- 需要根据运行时条件动态选择创建哪种对象
- 希望隐藏具体类的实现细节(例如SDK开发)
工厂方法 vs 简单工厂
特性 | 工厂方法 | 简单工厂 |
---|---|---|
扩展性 | 新增产品只需加新工厂类 | 需要修改工厂类代码 |
符合开闭原则 | ✅ | ❌ |
复杂度 | 较高(需要维护更多类) | 较低 |
适用场景 | 大型项目、产品类型多 | 小型项目、产品类型少 |
场景1:需要创建多种类型对象,且这些对象有共同接口
实际案例:跨平台文件存储服务
假设你需要支持将文件存储到不同云服务(阿里云OSS、腾讯云COS、AWS S3),但它们的上传/下载接口不同。
python
from abc import ABC, abstractmethod
# 公共接口
class CloudStorage(ABC):
@abstractmethod
def upload_file(self, local_path: str, remote_path: str):
pass
@abstractmethod
def download_file(self, remote_path: str, local_path: str):
pass
# 具体产品:阿里云OSS
class AliyunOSS(CloudStorage):
def upload_file(self, local_path: str, remote_path: str):
print(f"[阿里云] 上传 {local_path} 到 {remote_path}")
def download_file(self, remote_path: str, local_path: str):
print(f"[阿里云] 下载 {remote_path} 到 {local_path}")
# 具体产品:腾讯云COS
class TencentCOS(CloudStorage):
def upload_file(self, local_path: str, remote_path: str):
print(f"[腾讯云] 上传 {local_path} 到 {remote_path}")
def download_file(self, remote_path: str, local_path: str):
print(f"[腾讯云] 下载 {remote_path} 到 {local_path}")
# 工厂根据配置选择实现
class CloudStorageFactory:
@staticmethod
def create_storage(provider: str) -> CloudStorage:
if provider == "aliyun":
return AliyunOSS()
elif provider == "tencent":
return TencentCOS()
else:
raise ValueError("不支持的云服务商")
# 客户端代码无需知道具体实现
storage = CloudStorageFactory.create_storage("aliyun")
storage.upload_file("data.txt", "backup/data.txt")
场景2:创建过程涉及复杂初始化逻辑
实际案例:构建数据库连接对象
数据库连接需要处理参数校验、连接池初始化、超时设置等复杂步骤。
python
class DatabaseConnection:
def __init__(self, host: str, port: int, user: str, password: str):
# 复杂的初始化过程
self._validate_config(host, port)
self._init_connection_pool()
self._set_timeout(30)
print(f"已连接到 {host}:{port}")
def _validate_config(self, host, port):
if not host:
raise ValueError("Invalid host")
# 更多校验逻辑...
def _init_connection_pool(self):
print("初始化连接池...")
def _set_timeout(self, seconds):
print(f"设置超时时间:{seconds}秒")
class DatabaseFactory:
@staticmethod
def create_connection(config: dict) -> DatabaseConnection:
# 封装所有复杂逻辑
return DatabaseConnection(
host=config["host"],
port=config["port"],
user=config["user"],
password=config["password"]
)
# 使用示例
config = {
"host": "127.0.0.1",
"port": 3306,
"user": "admin",
"password": "secret"
}
db = DatabaseFactory.create_connection(config)
场景3:运行时动态选择创建哪种对象
实际案例:根据操作系统创建不同风格的UI组件
在跨平台应用中,需要根据当前操作系统动态创建对应风格的按钮。
python
import platform
# 抽象产品:按钮
class Button(ABC):
@abstractmethod
def render(self):
pass
# 具体产品:Windows风格按钮
class WindowsButton(Button):
def render(self):
print("渲染一个Windows风格的按钮")
# 具体产品:Mac风格按钮
class MacButton(Button):
def render(self):
print("渲染一个Mac风格的按钮")
class UIFactory:
@staticmethod
def create_button() -> Button:
# 根据运行时系统类型决定
os_name = platform.system()
if os_name == "Windows":
return WindowsButton()
elif os_name == "Darwin": # macOS
return MacButton()
else:
raise NotImplementedError("不支持的操作系统")
# 客户端代码
button = UIFactory.create_button()
button.render() # 输出取决于当前操作系统
场景4:隐藏具体实现细节(SDK开发)
实际案例:支付SDK封装
作为SDK提供方,你希望隐藏支付宝/微信支付的具体实现,只暴露统一接口。
python
# SDK对外暴露的接口
class PaymentProcessor(ABC):
@abstractmethod
def pay(self, amount: float):
pass
# 具体实现1(SDK内部实现)
class AlipayProcessor(PaymentProcessor):
def pay(self, amount: float):
print(f"调用支付宝接口支付 {amount} 元")
# 具体实现2(SDK内部实现)
class WechatPayProcessor(PaymentProcessor):
def pay(self, amount: float):
print(f"调用微信支付接口支付 {amount} 元")
class PaymentFactory:
@staticmethod
def create_processor(payment_type: str) -> PaymentProcessor:
if payment_type == "alipay":
return AlipayProcessor()
elif payment_type == "wechat":
return WechatPayProcessor()
else:
raise ValueError("不支持的支付方式")
# 开发者使用SDK时
processor = PaymentFactory.create_processor("alipay")
processor.pay(100.0) # 开发者无需知道支付宝的具体实现
总结:工厂模式的核心价值
场景 | 解决的问题 | 实际效果 |
---|---|---|
多种类型对象 + 共同接口 | 统一不同实现的访问方式 | 客户端代码无需关心具体类型 |
复杂初始化逻辑 | 封装创建细节避免代码重复 | 简化调用方代码,集中管理创建逻辑 |
运行时动态选择 | 避免在业务代码中写大量if-else | 提升代码可维护性 |
隐藏实现细节(如SDK) | 降低使用方与实现的耦合度 | 方便后续替换实现而不影响调用方 |
通过工厂模式,你可以将 变化的创建逻辑 与 稳定的业务逻辑 分离,这正是面向对象设计原则中「封装变化」的经典体现。