有勇气的牛排博客

Python 设计模式之策略模式

有勇气的牛排 15 Python 2025-08-01 22:22:56

Python 设计模式之 策略模式

1 前言

1.1 什么是策略模式?

策略模式(Strategy Pattern)是一种行为设计模式,定义一系列可互换的算法,把它们各自封装起来,并使它们可以相互替换,而不影响客户端的使用。

通俗讲:

  • 有多个可选策略(算法),可以按需选择并动态切换。
  • 客户端不关心用的是哪种策略,只要遵守接口就能用。

1.2 结构图(经典写法)

[Context上下文] | ↓ [Strategy接口]←── [具体策略A] [具体策略B]
  • Context:上下文,持有一个策略对象。
  • Strategy:抽象策略类(Python中通常是协议或接口)
  • ConcreteStrategy:具体策略实现。

1.3 设计思路

传统写法(不适用策略模式)可能会用 if-else 判断:

if mode == "add": result = a + b else mode == "sub": result = a - b

这样的问题是:

  • 如果有新的算法,需要修改调用方法。
  • 条件分支会越来越多,不利于维护。

策略模式的改进思路:

  • 定义一个策略接口(Strategy)。
  • 每个算法实现一个策略类,实现该接口。
  • 在运行时选择策略对象。

1.4 常见场景

  • 电商系统中不同支持防止(微信、支付宝、银行卡)。
  • 数据排序时选择不同排序算法。
  • 图片压缩时选择不同压缩方式。
  • 机器学习模型中选择不同训练策略。
  • 游戏中选择不同攻击行为。

1.5 优缺点

优点:

  • 解耦算法选择逻辑和实现
  • 新增策略类不影响已有代码(开放封闭原则)
  • 可动态切换行为,扩展性强
  • 消除了大量 if-else语句
  • 算法可以自由切换,符合开闭原则(OCP)

缺点:

  • 会增加类或函数数量,管理复杂
  • 客户端需要知道所有策略,并主动选择

2 基本案例

2.1 面向对象版本

# -*- coding: utf-8 -*- # 策略解耦(使用Protocol 方便类型检查) from typing import Protocol class Strategy(Protocol): def execute(self, a: int, b: int) -> int: ... # 具体策略实现 class AddStrategy: def execute(self, a: int, b: int): return a + b class SubStrategy: def execute(self, a: int, b: int): return a - b class MulStrategy: def execute(self, a: int, b: int): return a * b # 上下文类 class Calculator: def __init__(self, strategy: Strategy): self.strategy = strategy def set_strategy(self, strategy: Strategy): """允许在运行时切换策略""" self.strategy = strategy def calculate(self, a: int, b: int) -> int: return self.strategy.execute(a, b) # ===== 测试 ===== if __name__ == "__main__": calc = Calculator(AddStrategy()) print("加法:", calc.calculate(5, 3)) # 输出 8 calc.set_strategy(SubStrategy()) print("减法:", calc.calculate(5, 3)) # 输出 2 calc.set_strategy(MulStrategy()) print("乘法:", calc.calculate(5, 3)) # 输出 15

2.2 函数式(Pythonic)版

由于 Python 支持 函数作为一等对象,可以直接用函数替代策略类。

# -*- coding: utf-8 -*- def add(a, b): return a + b def sub(a, b): return a - b def mul(a, b): return a * b class Calculator: def __init__(self, strategy): self.strategy = strategy def set_strategy(self, strategy): self.strategy = strategy def calculate(self, a, b): return self.strategy(a, b) calc = Calculator(add) print("加法:", calc.calculate(5, 3)) calc.set_strategy(sub) print("减法:", calc.calculate(5, 3)) calc.set_strategy(mul) print("乘法:", calc.calculate(5, 3))

优点:更简洁,符合 Python 风格。

缺点:没有类的结构,可能在大型系统中可读性稍差。

3 支付策略模式

# -*- coding: utf-8 -*- from abc import ABC, abstractmethod # 策略接口 class PaymentStrategy(ABC): @abstractmethod def pay(self, amount: float) -> None: pass # 支付宝策略 class AliPayStrategy(PaymentStrategy): def pay(self, amount: float) -> bool: print(f"[支付宝] 支付 {amount} 元成功") return True # 微信策略 class WeChatPayStrategy(PaymentStrategy): def pay(self, amount: float) -> bool: print(f"[微信] 支付 {amount} 元成功") return True # 银行卡策略 class BankCardPayStrategy(PaymentStrategy): def pay(self, amount: float) -> bool: print(f"[银行卡] 支付 {amount} 元成功") return True # 支付上下文 class PaymentContext: def __init__(self, strategy: PaymentStrategy): self.strategy = strategy def execute_payment(self, amount: float) -> bool: return self.strategy.pay(amount) # 策略映射表 STRATEGY_MAP = { "alipay": AliPayStrategy, "wechat": WeChatPayStrategy, "bank": BankCardPayStrategy, } # 模拟后端接收请求 def handle_payment_request(pay_type: str, amount: float): strategy_class = STRATEGY_MAP.get(pay_type) if not strategy_class: raise ValueError(f"不支持的支付方式: {pay_type}") context = PaymentContext(strategy_class()) return context.execute_payment(amount) # ===== 测试 ===== if __name__ == "__main__": handle_payment_request("alipay", 100.0) handle_payment_request("wechat", 200.0) handle_payment_request("bank", 500.0)

image.png

评论区

×
×