工厂方法模式(Factory Method)

在真实项目中,对象的创建往往比使用更复杂 。

如果你发现代码中频繁出现 if-else 或根据参数去 new 不同的类,那基本已经到了该用工厂方法模式的时候了。


一、工厂方法模式解决什么问题

先看一个非常常见的写法:

python 复制代码
def create_payment(pay_type):
    if pay_type == "wechat":
        return WeChatPay()
    elif pay_type == "alipay":
        return AliPay()
    elif pay_type == "bank":
        return BankPay()
    else:
        raise ValueError("unsupported pay type")

问题很明显:

  • 新增一种支付方式,必须修改这个函数
  • 创建逻辑与业务逻辑耦合
  • 违反开闭原则

工厂方法模式的目的就是:

把"创建对象的逻辑"从使用对象的地方解耦出来。


二、什么是工厂方法模式

**工厂方法模式(Factory Method)**的定义:

定义一个创建对象的接口,让子类决定实例化哪一个类。

核心思想:

  • 使用方只依赖抽象
  • 创建细节由工厂或子类负责

三、一个最基础的 Python 工厂方法示例

1. 抽象产品

python 复制代码
from abc import ABC, abstractmethod

class Payment(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

2. 具体产品

python 复制代码
class WeChatPay(Payment):
    def pay(self, amount):
        print(f"微信支付 {amount}")

class AliPay(Payment):
    def pay(self, amount):
        print(f"支付宝支付 {amount}")

3. 工厂类

python 复制代码
class PaymentFactory:
    @staticmethod
    def create(pay_type: str) -> Payment:
        if pay_type == "wechat":
            return WeChatPay()
        if pay_type == "alipay":
            return AliPay()
        raise ValueError("unsupported pay type")

使用方:

python 复制代码
payment = PaymentFactory.create("wechat")
payment.pay(100)

四、为什么这还不够"工厂方法"

上面的写法虽然集中管理了创建逻辑,但:

  • 依然需要修改工厂代码
  • 本质还是 if-else

真正的工厂方法强调:

通过继承扩展工厂,而不是修改工厂。


五、标准工厂方法模式结构

1. 抽象工厂

python 复制代码
class PaymentFactory(ABC):
    @abstractmethod
    def create(self) -> Payment:
        pass

2. 具体工厂

python 复制代码
class WeChatPayFactory(PaymentFactory):
    def create(self) -> Payment:
        return WeChatPay()

class AliPayFactory(PaymentFactory):
    def create(self) -> Payment:
        return AliPay()

使用方式:

python 复制代码
factory = WeChatPayFactory()
payment = factory.create()
payment.pay(100)

新增支付方式时:

  • 新增产品类
  • 新增工厂类
  • 无需修改原有代码

六、Python 风格的工厂方法(推荐)

Python 中,很多时候没必要写那么多类。

使用字典 + 类引用

python 复制代码
class PaymentFactory:
    _mapping = {
        "wechat": WeChatPay,
        "alipay": AliPay,
    }

    @classmethod
    def create(cls, pay_type: str) -> Payment:
        try:
            return cls._mapping[pay_type]()
        except KeyError:
            raise ValueError("unsupported pay type")

优点:

  • 代码简洁
  • 易于维护
  • 更符合 Python 风格

七、工厂方法 vs 直接实例化

对比点 直接 new 工厂方法
扩展性 差 好
解耦 低 高
可测试性 差 好
代码复杂度 低 中

适用原则:

  • 对象类型固定、变化少 → 直接实例化
  • 对象类型多、变化频繁 → 工厂方法

八、工厂方法常见误区

1. 工厂类变成"上帝类"

  • 包含大量 if-else
  • 违反单一职责

解决方案:

  • 拆分工厂
  • 或引入抽象工厂

2. 为了工厂而工厂

  • 只有一个实现类
  • 没有扩展需求

👉 直接实例化即可。


九、总结

工厂方法模式的核心价值在于:

  • 解耦创建与使用
  • 遵循开闭原则
  • 为系统预留扩展空间

在 Python 中:

  • 思想比形式重要
  • 不必拘泥 UML 结构
  • 用最简单的方式解决创建问题
相关推荐
captain3762 小时前
MyBatis(入门5)其他查询操作
java·数据库·spring boot·mybatis
Novproxy_Z3 小时前
商用代理避坑:如何识别商家拿机房 IP 冒充住宅 IP
java·网络·tcp/ip
无足鸟ICT3 小时前
【RHCA+】vmstat命令(监控系统资源)
linux·服务器
垆边人似月.3 小时前
RDMA 文件传输踩坑(五):READY 发送成功后,为什么出现 Work Request Flushed Error?
服务器·网络·tcp/ip
闪亮的路灯3 小时前
Linux 安装mqtt服务mosquitto
linux·运维·服务器
前端精髓3 小时前
结构化输出with_structured_output(抽卡)
python·langchain
HideF3 小时前
nmcli
linux·服务器·网络
文丑颜不良啊4 小时前
LeetCode1481~1500题目解析
java·leetcode
2601_962885724 小时前
quotes 字段全解:涨跌幅、振幅、换手率的口径与单位
java·前端·spring
前端精髓4 小时前
调用openrouter的免费API模型
java·前端·javascript