工厂模式与策略模式对比

一、工厂模式与策略模式对比

1.1 工厂模式:没工厂会怎样?

 
# 场景:支付系统,支持微信支付和支付宝。没工厂模式时:
 
class WechatPay:                         # 微信支付类
 
    def pay(self, amount):               # 支付方法
 
        print(f"微信支付 {amount} 元")    # 调用微信 API
 
class Alipay:                            # 支付宝类
 
    def pay(self, amount):               # 支付方法
 
        print(f"支付宝支付 {amount} 元")  # 调用支付宝 API
 
# 每次要用支付,调用方得自己判断 new 哪个:
 
method = "wechat"                        # 假设从请求里拿到支付方式
 
if method == "wechat":                   # ① 调用方要写 if-else 判断
 
    payer = WechatPay()                  # ② 调用方自己 new
 
elif method == "alipay":                 # ③ 每次加新支付方式
 
    payer = Alipay()                     # ④ 这里要加一个 elif
 
elif method == "unionpay":               # ⑤ 假设又加了银联
 
    payer = UnionPay()                   # ⑥ if-else 越来越长……
 
payer.pay(100)                           # ⑦ 终于可以支付了
 
# 加一种新支付方式 → 所有调用支付的地方都要改 if-else。
 

执行流程(if-else 版本的逐步追踪)

 
第1步:method = "wechat" → 字符串赋值,假设来自 HTTP 请求参数 ?method=wechat
 
第2步:if method == "wechat": → True
 
         → payer = WechatPay() → 调 WechatPay.__init__ → 创建微信支付实例
 
         → payer 指向这个实例
 
第3步:跳过后面的 elif(已经匹配到第一个)
 
第4步:payer.pay(100) → 调 WechatPay.pay → 输出 "微信支付 100 元"
 
—— 看起来还行?现在加银联 ——
 
第5步:需要加 elif method == "unionpay": → payer = UnionPay()
 
         → 问题:每加一种支付方式,这里的 if-elif 就要加一行
 
         → 如果项目里有 10 个地方都这样判断支付方式 → 改 10 处
 
         → 漏改一处 → 银联支付在那个页面报错 "不支持的支付方式"
 

1.2 工厂模式:简单工厂(最常用,手写这个)

 
# 简单工厂 = 一个函数/一个类,根据参数创建不同对象
 
class WechatPay:                         # 微信支付类
 
    def pay(self, amount):               # 支付方法
 
        print(f"微信支付 {amount} 元")    # 实现微信接口
 
class Alipay:                            # 支付宝类
 
    def pay(self, amount):               # 支付方法
 
        print(f"支付宝支付 {amount} 元")  # 实现支付宝接口
 
class PaymentFactory:                    # 支付工厂——专门负责创建支付对象
 
    @staticmethod                        # 静态方法:不用建工厂实例就能调
 
    def create_payment(method: str):     # 入参:支付方式字符串
 
        if method == "wechat":           # ① 要微信 → 创建微信支付
 
            return WechatPay()           # ② 返回微信支付实例
 
        elif method == "alipay":         # ③ 要支付宝 → 创建支付宝
 
            return Alipay()              # ④ 返回支付宝实例
 
        else:                            # ⑤ 不支持的类型
 
            raise ValueError(f"不支持的支付方式: {method}")  # ⑥ 抛异常
 
# 调用方代码——多干净:
 
payer = PaymentFactory.create_payment("wechat")  # 一步拿到支付对象,不用管怎么 new 的
 
payer.pay(100)                           # 支付 100 元
 
# 加新的支付方式:只改工厂函数,调用方一行不动!
 

执行流程(简单工厂逐行追踪)

 
第1步:Python 执行 class WechatPay: → 定义微信支付类
 
第2步:Python 执行 class Alipay: → 定义支付宝类
 
第3步:Python 执行 class PaymentFactory: → 定义工厂类
 
         → @staticmethod 标记 create_payment 为静态方法(不需要 self)
 
第4步:payer = PaymentFactory.create_payment("wechat")
 
         → 直接调 PaymentFactory.create_payment("wechat")
 
           → method = "wechat"
 
           → if method == "wechat": → True
 
           → return WechatPay() → 创建 WechatPay 实例(假设 0xEEEE)
 
         → payer = 0xEEEE
 
第5步:payer.pay(100)
 
         → Python 查找 0xEEEE.pay → 找到 WechatPay.pay
 
         → 调 pay(0xEEEE, 100) → self = 0xEEEE, amount = 100
 
         → print("微信支付 100 元")
 
—— 加新支付方式流程 ——
 
第6步:写 class UnionPay: def pay(self, amount): ...(新类,不改已有代码)
 
第7步:在 PaymentFactory.create_payment 里加 elif method == "unionpay": return UnionPay()
 
         → 只改一处!调用方 payer.pay(100) 不需要改
 
         → 因为调用方只依赖工厂返回的对象的 .pay() 方法,不关心具体类名
 

1.3 工厂模式:工厂方法(进阶亮点)

简单工厂:一个工厂类根据 if-else 创建不同产品。

工厂方法:一个抽象工厂类定义”创建产品”的接口,具体创建什么由子类决定。

 
from abc import ABC, abstractmethod      # ABC = 抽象基类(Abstract Base Class)
 
# ① 定义产品接口——所有支付方式必须实现 pay 方法
 
class PaymentProcessor(ABC):             # 抽象产品:约束所有支付类必须有 pay
 
    @abstractmethod                      # 抽象方法——子类必须实现,不然报错
 
    def pay(self, amount):              # 支付方法签名
 
        pass                             # 抽象方法不写实现
 
# ② 具体产品——每种支付方式各自实现
 
class WechatPay(PaymentProcessor):       # 继承抽象产品
 
    def pay(self, amount):               # 实现支付(必须写,不然报错)
 
        print(f"微信支付 {amount} 元")
 
class Alipay(PaymentProcessor):          # 另一个具体产品
 
    def pay(self, amount):               # 实现支付
 
        print(f"支付宝支付 {amount} 元")
 
# ③ 定义工厂接口——所有工厂必须实现 create 方法
 
class PaymentFactory(ABC):               # 抽象工厂
 
    @abstractmethod
 
    def create_payment(self) -> PaymentProcessor:  # 返回一个支付处理器
 
        pass                             # 子工厂决定具体返回什么
 
# ④ 具体工厂——每个工厂只负责创建一种支付方式
 
class WechatFactory(PaymentFactory):     # 微信工厂
 
    def create_payment(self) -> PaymentProcessor:  # 实现创建方法
 
        return WechatPay()               # 只创建微信支付
 
class AlipayFactory(PaymentFactory):     # 支付宝工厂
 
    def create_payment(self) -> PaymentProcessor:  # 实现创建方法
 
        return Alipay()                  # 只创建支付宝
 
# 使用:
 
factory = WechatFactory()                # 选微信工厂
 
payer = factory.create_payment()         # 工厂帮你创建支付对象(调用方不知道创建细节)
 
payer.pay(100)                           # 微信支付 100 元
 
# 要加银联支付?写一个 UnionFactory + UnionPay,不改任何已有代码(开闭原则)
 

执行流程(工厂方法逐行追踪)

 
第1步:Python 执行 class PaymentProcessor(ABC): → 创建抽象产品类
 
         → @abstractmethod 标记 pay → 子类不实现就报 TypeError
 
第2步:Python 执行 class WechatPay(PaymentProcessor): → 具体产品类
 
         → def pay(self, amount): 实现 → 满足抽象方法要求,通过检查
 
第3步:Python 执行 class Alipay(PaymentProcessor): → 同上
 
第4步:Python 执行 class PaymentFactory(ABC): → 创建抽象工厂类
 
         → @abstractmethod 标记 create_payment
 
第5步:Python 执行 class WechatFactory(PaymentFactory): → 具体工厂类
 
         → def create_payment(self): return WechatPay()
 
         → 只负责创建微信支付,单一职责
 
第6步:factory = WechatFactory() → 创建微信工厂实例(0xFFFF)
 
第7步:payer = factory.create_payment()
 
         → Python 调 WechatFactory.create_payment(0xFFFF)
 
         → return WechatPay() → 创建 WechatPay 实例(0xGGGG)
 
         → payer = 0xGGGG
 
第8步:payer.pay(100)
 
         → Python 查找 0xGGGG.pay → WechatPay.pay
 
         → print("微信支付 100 元")
 
—— 和简单工厂的关键区别 ——
 
简单工厂:PaymentFactory.create_payment("wechat") → 工厂内部 if-else 判断
 
工厂方法:WechatFactory().create_payment() → 子类决定,连 if-else 都省了
 
扩展性:加银联 → 简单工厂要改 create_payment 的 if-else(改已有代码)
 
                 → 工厂方法新增 UnionFactory + UnionPay 两个新文件(不改已有代码)
 
简单工厂工厂方法
产品类型固定 2-3 种会频繁新增
代码量很少多(每个产品配一个工厂)
扩展性改工厂的 if-else(违反开闭原则)新增子类(不碰已有代码)
手写简单工厂最常用说出工厂方法概念即可
实际项目90% 的情况简单工厂够了插件系统、框架扩展点

原则:先简单工厂。等 if-else 超过 5 个、或者每次加产品都要改工厂时,再升级工厂方法。

1.4 工厂模式的本质

 
工厂模式 = 把"创建对象的代码"和"使用对象的代码"拆开。
 
没工厂:调用方自己 new → 调用方依赖所有具体类 → 加新类要改调用方
 
有工厂:调用方只依赖工厂 → 工厂依赖具体类 → 加新类只改工厂
 

类比 Python 里你早就见过的工厂:open("a.txt") 就是工厂函数——你传”文件名”,它返回文件对象。你不用管文件在硬盘哪个扇区、怎么分配缓冲区。一切 API/库函数本质上都是”工厂”——封装创建细节,给你一个能用的对象。


1.5 策略模式:没策略会怎样?

 
# 场景:电商促销——普通用户不打折、VIP 打 8 折、超级 VIP 打 6 折
 
def calculate_price(user_type, original_price):  # 计算最终价格
 
    if user_type == "normal":                    # ① 普通用户
 
        return original_price                    # ② 原价
 
    elif user_type == "vip":                     # ③ VIP 用户
 
        return original_price * 0.8              # ④ 8 折
 
    elif user_type == "svip":                    # ⑤ 超级 VIP
 
        return original_price * 0.6              # ⑥ 6 折
 
    elif user_type == "new_user":                # ⑦ 新增:新用户首单 7 折
 
        return original_price * 0.7              # ⑧ 每次加策略都要改这个函数
 
    # 每加一种用户类型 → if-elif 越来越长 → 这个函数最后变成百行怪兽
 
# ③ 违反"开闭原则"——对扩展开放(可以加策略),对修改也开放(要改原函数)
 

执行流程(if-elif 版本逐步追踪)

 
第1步:calculate_price("vip", 100)
 
         → user_type = "vip", original_price = 100
 
         → if user_type == "normal" → False,跳过
 
         → elif user_type == "vip" → True!进入
 
         → return 100 * 0.8 → 返回 80
 
第2步:calculate_price("svip", 100)
 
         → 前两个条件 False → elif user_type == "svip" → True → 返回 60
 
—— 加新用户类型 new_user ——
 
第3步:需要在函数体里加 elif user_type == "new_user": return price * 0.7
 
         → 改了 calculate_price 函数本身
 
         → 如果改的时候手滑删了 vip 那行的 * 0.8 → VIP 变成原价 → 线上事故
 
         → 每加一个类型就动一次"已经在线上稳定运行"的函数 → 风险累积
 
第4步:如果另一个文件也有类似的折扣计算 → 两处都要加 → 漏一处就行为不一致
 

1.6 策略模式——函数版(Python 一等公民,极简版)

Python 里实现策略模式比 Java 简单一个数量级——因为 Python 函数可以直接当参数传。不需要定义接口、不需要策略类,一个函数就是一个策略。

 
# === 定义策略:每个策略就是一个普通函数 ===
 
def normal_discount(price):              # ① 普通用户策略:不打折
 
    return price                         #    原价返回
 
def vip_discount(price):                 # ② VIP 策略:8 折
 
    return price * 0.8                   #    打八折
 
def svip_discount(price):                # ③ 超级 VIP 策略:6 折
 
    return price * 0.6                   #    打六折
 
# === 上下文:使用策略的地方 ===
 
def calculate_price(discount_strategy, original_price):  # ① 策略函数作为参数传入
 
    return discount_strategy(original_price)              # ② 调策略函数,不关心具体是哪个
 
# === 使用 ===
 
price = calculate_price(vip_discount, 100)   # 传入 vip 策略 → 80
 
price = calculate_price(svip_discount, 100)  # 换成 svip 策略 → 60
 
# 加新策略?再写一个函数,传进去就行——不改 calculate_price 一行代码
 

执行流程(函数版策略逐行追踪)

 
第1步:Python 执行 def normal_discount(price): → 函数对象创建,存入全局命名空间
 
         → normal_discount 现在是一个可调用的函数对象(类似一个变量)
 
第2步:同样,vip_discount 和 svip_discount 函数对象创建
 
第3步:Python 执行 def calculate_price(discount_strategy, original_price):
 
         → 这个函数接收两个参数:函数对象 + 数字
 
         → 函数体内:discount_strategy(original_price) → 把第二个参数传给第一个参数(函数)并调用
 
第4步:执行 price = calculate_price(vip_discount, 100)
 
         → discount_strategy = vip_discount(函数对象本身,不是调用结果)
 
         → original_price = 100
 
         → return vip_discount(100) → 进入 vip_discount 函数体
 
           → price = 100 → return 100 * 0.8 → 返回 80
 
         → price = 80
 
第5步:执行 price = calculate_price(svip_discount, 100)
 
         → 同上,但 discount_strategy = svip_discount → 返回 60
 
—— 加新策略 new_user ——
 
第6步:def new_user_discount(price): return price * 0.7 → 新函数,不碰 calculate_price
 
第7步:calculate_price(new_user_discount, 100) → 传入新函数即可
 
         → calculate_price 的代码一行没动 → 零风险
 

核心机制:Python 函数是”一等公民”——函数对象可以像 int、str 一样当参数传递。calculate_price 不知道也不关心传入的函数叫什么、怎么实现的,只负责”调用它”。

1.7 策略模式——类版(写这个,显得”正式”)

 
from abc import ABC, abstractmethod      # 导入抽象基类
 
# ① 策略接口(Python 里非必须,但写出来是加分亮点)
 
class DiscountStrategy(ABC):             # 折扣策略抽象基类
 
    @abstractmethod
 
    def calculate(self, price):          # 抽象方法:计算折扣后价格
 
        pass
 
# ② 具体策略类
 
class NormalDiscount(DiscountStrategy):  # 普通用户策略
 
    def calculate(self, price):          # 实现:原价
 
        return price
 
class VipDiscount(DiscountStrategy):     # VIP 策略
 
    def calculate(self, price):          # 实现:8 折
 
        return price * 0.8
 
class SvipDiscount(DiscountStrategy):    # 超级 VIP 策略
 
    def calculate(self, price):          # 实现:6 折
 
        return price * 0.6
 
# ③ 上下文——持有策略并使用
 
class Order:                             # 订单类
 
    def __init__(self, discount_strategy: DiscountStrategy):  # 注入策略对象
 
        self.discount_strategy = discount_strategy            # 保存策略
 
    def get_price(self, original_price):                      # 计算最终价格
 
        return self.discount_strategy.calculate(original_price)  # 委托给策略对象计算
 
# 使用——策略可以运行时随意换
 
order = Order(NormalDiscount())          # 先用普通策略
 
print(order.get_price(100))              # 100
 
order.discount_strategy = VipDiscount()  # 换成 VIP 策略(运行时换!)
 
print(order.get_price(100))              # 80
 
# 不用改 Order 类一行代码,策略随便换
 

执行流程(类的写法逐行追踪)

 
第1步:Python 执行 class DiscountStrategy(ABC): → 抽象策略接口定义
 
         → @abstractmethod 标记 calculate,子类必须实现
 
第2步:class NormalDiscount(DiscountStrategy): → 定义原价策略
 
         → def calculate(self, price): return price → 实现抽象方法
 
第3步:class VipDiscount / SvipDiscount → 定义 8 折 / 6 折策略
 
第4步:class Order: → 定义订单类
 
         → __init__ 接收 discount_strategy 参数并保存到 self.discount_strategy
 
         → get_price 委托给策略对象计算
 
第5步:order = Order(NormalDiscount())
 
         → NormalDiscount() 先执行 → 创建策略实例(0xHHHH)
 
         → Order.__init__(order_实例, 0xHHHH) → self.discount_strategy = 0xHHHH
 
         → order 指向 Order 实例(0xJJJJ)
 
第6步:order.get_price(100)
 
         → self = 0xJJJJ, original_price = 100
 
         → self.discount_strategy = 0xHHHH(NormalDiscount 实例)
 
         → 调 0xHHHH.calculate(100) → NormalDiscount.calculate → return 100
 
         → 返回 100
 
第7步:order.discount_strategy = VipDiscount()
 
         → VipDiscount() 创建新策略实例(0xKKKK)
 
         → order.discount_strategy 从 0xHHHH 变为 0xKKKK(运行时切换!)
 
第8步:order.get_price(100)
 
         → 现在 self.discount_strategy = 0xKKKK(VipDiscount 实例)
 
         → 调 0xKKKK.calculate(100) → return 100 * 0.8 → 返回 80
 
         → Order 类的 get_price 代码一行没变,但行为从"原价"变成了"8 折"
 

关键:策略对象和上下文对象(Order)是”组合”关系,不是”继承”关系。策略随时可以换,Order 只依赖 DiscountStrategy 接口,不依赖具体策略类。

  • 驾车策略(走高速)→ CarStrategy

  • 公交策略(坐地铁)→ BusStrategy

  • 步行策略(抄近路)→ WalkStrategy

同一个目的地(同样的输入),换一个策略就是另一条路线。导航引擎(Order 类)不关心你选什么策略——它只调用 strategy.calculate(),具体怎么走是策略自己的事。

1.8 策略模式 vs if-else(关键对比)

 
# ❌ if-else 版:加策略 = 改主函数(违反开闭原则)
 
def calc_price(user_type, price):
 
    if user_type == "normal":
 
        return price
 
    elif user_type == "vip":
 
        return price * 0.8
 
    # 加新类型 → 改这里,可能改坏已有的
 
# ✅ 策略模式版:加策略 = 新增一个函数/类(主函数不动)
 
def calc_price(strategy, price):
 
    return strategy(price)               # 策略从外面传进来,主函数永不改
 
# 加新折扣 → 写一个新函数,传进来即可
 

执行流程(两种写法的对比追踪)

 
if-else 版加策略:
 
  ① 打开 calc_price 函数 → 在 elif 链末尾加 elif user_type == "new": return price * 0.7
 
  ② 改动了 calc_price 的源代码 → 所有依赖 calc_price 的调用方都受影响
 
  ③ 如果改错了(比如复制粘贴漏改打折比例)→ 所有调用方一起坏
 
策略模式版加策略:
 
  ① def new_strategy(price): return price * 0.7 → 新函数,独立文件/独立位置
 
  ② calc_price(new_strategy, 100) → 调用方传入新函数
 
  ③ calc_price 源代码不受影响 → 已有的 normal/vip 策略完全不受牵连
 
  ④ 单元测试:new_strategy 可以独立测试,不依赖 calc_price
 
场景可变策略具体例子
支付微信/支付宝/银行卡订单结算时选支付方式
折扣满减/打折/立减/拼团电商促销规则引擎
排序价格/销量/评分/时间商品列表排序切换
导出PDF/Excel/CSV报表导出格式切换
验证手机号/邮箱/身份证表单校验规则
压缩zip/gzip/brotliHTTP 响应压缩

策略模式是消除 if-else 链的第一武器。当你发现代码里同一个位置有 3 个以上 elif 且还在增长 → 策略模式在召唤你。


1.9 工厂 vs 策略:何时用哪个?

两个模式都能消除 if-else,但解决的问题根本不同。常见追问:“工厂模式和策略模式有什么区别?”

一句话区分

  • 工厂模式解决的是”创建谁”——你关心拿到什么对象

  • 策略模式解决的是”怎么做”——你关心行为怎么切换


flowchart LR

    A["调用方"] -->|"需要对象"| B["工厂模式<br/>帮你创建"]

    A -->|"需要行为"| C["策略模式<br/>帮你切换"]

    B --> D["返回具体对象<br/>WechatPay / Alipay"]

    C --> E["注入具体策略<br/>vip_discount / svip_discount"]

类比

生活场景工厂模式策略模式
去餐厅前台帮你”创建”一盘菜 → 你不用管厨房怎么炒你选”辣度策略” → 微辣/中辣/变态辣,同一道菜换策略就换口味
出行订票平台帮你”创建”一趟航班 → 你拿到票就行你选”出行策略” → 飞机/高铁/自驾,目的地相同但方式不同
买电脑苹果商店帮你”创建”一台 Mac → 你不用管供应链你选”付款策略” → 全款/分期/花呗,同一台电脑付款方式不同

核心差异对照表

维度工厂模式策略模式
解决什么对象创建的耦合行为切换的 if-else
关注点拿到什么(WHAT)怎么做(HOW)
变化点产品类型增多算法/规则增多
调用方依赖只依赖工厂接口只依赖策略接口
扩展方式新增产品类 + 注册到工厂新增策略类/函数
if-else 消除位置创建对象的代码执行逻辑的代码
典型场景日志框架选 logger、DAO 选数据库折扣规则、排序算法、压缩算法

两者可以组合使用

 
# ① 工厂:根据用户选择创建支付方式
 
payer = PaymentFactory.create_payment("wechat")  # 工厂帮你创建支付对象
 
# ② 策略:根据用户等级决定折扣
 
order = Order(VipDiscount())                     # 策略注入折扣算法
 
final_price = order.get_price(100)               # 先算折扣
 
payer.pay(final_price)                            # 再支付
 

工厂和策略就像餐厅的”厨房”和”菜单调料台”——厨房负责做出菜(创建对象),调料台负责调整口味(切换行为)。你不会因为想换辣度就让厨房重新炒一道菜,也不会因为换了菜品就改变辣度策略。两者独立变化,组合使用。

速记口诀

工厂管创建,策略管行为

工厂是”厨房出菜”,策略是”调料换味”。

两个都能消 if-else,但一个消在 new 前面,一个消在 elif 后面。


速记卡(面试闪卡)

Q1:一句话讲清「工厂模式与策略模式对比」到底是什么?

A:工厂模式管”创建什么对象”,策略模式管”行为怎么切换”——一个消在 new 前,一个消在 elif 后。

Q2:一、工厂模式 —— 怎么理解? —— 怎么理解?

A:工厂像餐厅后厨——你点菜(传入参数)就拿到一盘做好的菜,不用管厨房怎么炒、哪个厨师做的。简单工厂用 if-else 返回对象;工厂方法让子类决定创建谁。核心:把”创建”和”使用”拆开(Creation pattern)。

Q3:二、策略模式 —— 怎么理解? —— 怎么理解?

A:策略像导航的”路线偏好”——同一目的地,换经济/最快/最短就换一条路,导航(上下文)不用改代码。Python 里函数是一等公民,一个函数就是一个策略,直接当参数传进来计算价格。核心:消除 if-else 链(Behavior pattern)。

Q4:三、工厂 vs 策略 本质区别 —— 怎么理解? —— 怎么理解?

A:一句话:工厂解决”拿到什么”(WHAT,对象是哪种),策略解决”怎么做”(HOW,行为怎么换)。两者都能消 if-else,但一个消在 new 前面,一个消在 elif 后面。两者可组合:工厂创建支付对象,策略决定折扣算法。

Q5:四、组合与口诀 —— 怎么理解? —— 怎么理解?

A:厨房(工厂)出菜、调料台(策略)换味——不会因为想换辣度就重炒一道菜。记:工厂负责”造物”,策略负责”换招”;一个管在 new 之前,一个管在 elif 之后,分工明确不打架。

Q6:核心速记主线有哪些?

  • 工厂模式:把”创建对象”从”使用对象”里拆出来

  • 策略模式:用函数/类封装可替换的算法,消 if-else

  • 工厂管 WHAT(拿什么对象),策略管 HOW(怎么行为)

  • 两者可组合:工厂建对象 + 策略选行为

口诀

A:工厂造物不用恼,

策略换招真轻巧;

new 前把那对象造,

elif 之后行为调。

相关链接