Python 中的策略模式(Strategy Pattern)
策略模式是一种行为型设计模式,其核心目的是:
定义一系列算法(策略),把它们一个个封装起来,并且使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
形象比喻:就像出行方式——你可以选择“开车”、“骑自行车”、“坐公交”作为出行策略,客户端(你)只需说“我要出行”,具体用哪种方式可以在运行时切换。
策略模式的优点
- 开闭原则:新增策略无需修改客户端代码
- 消除条件判断:避免一大堆 if-elif-else
- 复用性高:策略可以独立测试和复用
- 运行时灵活切换:动态选择不同行为
典型应用场景
- 排序算法选择(快速排序、归并排序、冒泡排序)
- 支付方式(支付宝、微信、银行卡)
- 压缩算法(ZIP、GZIP、RAR)
- 路径规划(最短路径、最快路径、避开收费站)
- 验证规则(不同表单的不同校验策略)
- 优惠计算(满减、打折、买赠)
Python 实现示例:支付系统
from abc import ABC, abstractmethod
# 策略接口(Strategy)
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: float) -> str:
pass
# 具体策略1:支付宝支付
class AlipayPayment(PaymentStrategy):
def pay(self, amount: float) -> str:
return f"通过支付宝支付 ¥{amount:.2f} 元(手续费 0.6%)"
# 具体策略2:微信支付
class WechatPayment(PaymentStrategy):
def pay(self, amount: float) -> str:
return f"通过微信支付 ¥{amount:.2f} 元(手续费 0%)"
# 具体策略3:银行卡支付
class BankCardPayment(PaymentStrategy):
def __init__(self, card_number: str):
self.card_number = card_number
def pay(self, amount: float) -> str:
masked = "*" * 12 + self.card_number[-4:]
return f"通过银行卡 {masked} 支付 ¥{amount:.2f} 元(手续费 1%)"
# 上下文(Context):持有策略引用
class ShoppingCart:
def __init__(self):
self.items = []
self._payment_strategy: PaymentStrategy = None
def add_item(self, name: str, price: float):
self.items.append((name, price))
def total_amount(self) -> float:
return sum(price for _, price in self.items)
def set_payment_strategy(self, strategy: PaymentStrategy):
self._payment_strategy = strategy
def checkout(self):
if not self._payment_strategy:
return "请先选择支付方式!"
amount = self.total_amount()
result = self._payment_strategy.pay(amount)
print(f"订单总金额: ¥{amount:.2f}")
print(result)
print("支付成功!\n")
return result
# 客户端使用(运行时自由切换策略)
if __name__ == "__main__":
cart = ShoppingCart()
cart.add_item("Python编程书籍", 89.0)
cart.add_item("机械键盘", 599.0)
cart.add_item("显示器", 1299.0)
# 策略1:支付宝支付
cart.set_payment_strategy(AlipayPayment())
cart.checkout()
# 策略2:微信支付
cart.set_payment_strategy(WechatPayment())
cart.checkout()
# 策略3:银行卡支付
cart.set_payment_strategy(BankCardPayment("6222021234567890"))
cart.checkout()
输出:
订单总金额: ¥1987.00
通过支付宝支付 ¥1987.00 元(手续费 0.6%)
支付成功!
订单总金额: ¥1987.00
通过微信支付 ¥1987.00 元(手续费 0%)
支付成功!
订单总金额: ¥1987.00
通过银行卡 ****7890 支付 ¥1987.00 元(手续费 1%)
支付成功!
Pythonic 更简洁实现:函数作为策略
Python 是动态语言,函数就是一等公民,可以用简单函数代替类来实现策略(推荐在策略简单时使用)。
from typing import Callable
# 定义策略类型
PaymentFunction = Callable[[float], str]
def alipay_pay(amount: float) -> str:
return f"支付宝支付 ¥{amount:.2f}"
def wechat_pay(amount: float) -> str:
return f"微信支付 ¥{amount:.2f}(免手续费)"
def credit_card_pay(card_number: str):
def inner(amount: float) -> str:
masked = "*" * 12 + card_number[-4:]
return f"信用卡 {masked} 支付 ¥{amount:.2f}"
return inner
class SimpleCart:
def __init__(self):
self.total = 0
self.pay_func: PaymentFunction = None
def set_total(self, total: float):
self.total = total
def set_strategy(self, strategy: PaymentFunction):
self.pay_func = strategy
def pay(self):
if self.pay_func:
print(self.pay_func(self.total))
# 使用
cart = SimpleCart()
cart.set_total(999.0)
cart.set_strategy(alipay_pay)
cart.pay()
cart.set_strategy(wechat_pay)
cart.pay()
card_strategy = credit_card_pay("1234567890123456")
cart.set_strategy(card_strategy)
cart.pay()
甚至更简单:用字典映射策略
strategies = {
"alipay": alipay_pay,
"wechat": wechat_pay,
"card": credit_card_pay("6222xxxxxxxxxxxx")
}
payment_type = "wechat"
strategies[payment_type](999.0)
策略模式结构总结
| 角色 | 说明 |
|---|---|
| Strategy | 抽象策略接口(PaymentStrategy) |
| ConcreteStrategy | 具体策略(AlipayPayment 等) |
| Context | 上下文,持有策略引用(ShoppingCart) |
策略模式 vs 其他模式对比
| 模式 | 目的 | 是否运行时切换 | 典型场景 |
|---|---|---|---|
| 策略 | 算法可替换 | 是 | 支付、排序、压缩 |
| 状态 | 对象状态变化导致行为变化 | 是 | 订单状态机 |
| 命令 | 将请求封装为对象 | 是 | 撤销、重做 |
| 模板方法 | 定义算法骨架,子类实现步骤 | 否(继承) | 固定流程的可变部分 |
Python 中的实用建议
- 策略简单:直接用函数或 lambda(最 Pythonic)
- 策略复杂或有状态:用类实现
- 大量策略:用字典或注册机制管理
- 结合枚举(
Enum)更清晰:
from enum import Enum
class PaymentType(Enum):
ALIPAY = AlipayPayment()
WECHAT = WechatPayment()
cart.set_payment_strategy(PaymentType.ALIPAY.value)
真实项目中的例子
- Django/Form 的字段验证策略
- Pandas 的
groupby().agg()支持多种聚合函数 - 机器学习模型选择(不同算法作为策略)
- 游戏 AI 行为切换(攻击、防御、逃跑策略)
策略模式是消除条件判断和实现行为可插拔的利器,在 Python 中由于函数式特性,实现起来特别优雅。
如果你想看更多实战例子(如排序策略、折扣计算策略、路径规划策略),或者如何与工厂模式结合使用,随时告诉我!