> 前言:在前面的章节中,我们重构了工厂与观察者模式。在设计模式的"行为型"家族中,策略模式(Strategy Pattern) 与 责任链模式(Chain of Responsibility Pattern) 常常充斥着大量的类继承、接口定义与繁琐的上下文切换。
> 随着 Python 3.10+ 引入 强化的模式匹配(Pattern Matching)、Callable 类型约束 以及 可空/联合类型语法(|),我们完全可以用面向函数(Functional Approach)和轻量级协议(Protocol)对这两个经典模式进行彻头彻尾的重构。
>
一、 策略模式:从 OOP 冗余到函数式一等公民
- 传统策略模式的"痛点"
在传统的 Java/C++ 式 OOP 编写方式中,策略模式通常需要:
* 定义一个抽象策略基类(或接口)。
* 为每一种具体算法(策略)继承并实现一个 StrategyClass。
* 定义一个 Context 上下文类来持有策略实例。
这种写法在 Python 中显得过于笨重,且创建了大量的无状态对象。
- Modern Python (3.10+) 演进方案:函数式策略 + 模式匹配
在 Python 中,函数是一等公民(First-class Function)。借助 collections.abc.Callable,我们可以将策略直接定义为可调用对象,省去繁琐的子类继承。
重构方案:订单折扣计算引擎
from typing import Callable, TypeAlias
from dataclasses import dataclass
from decimal import Decimal
定义策略类型别名:接收订单对象,返回折扣金额
DiscountStrategy: TypeAlias = Callable\["Order", Decimal]
@dataclass(slots=True, frozen=True)
def Order:
user_tier: str # "regular", "vip", "svip"
total_amount: Decimal
item_count: int
--- 具体的策略函数(彻底摒弃类继承) ---
def no_discount_strategy(order: Order) -> Decimal:
return Decimal("0.00")
def vip_discount_strategy(order: Order) -> Decimal:
return order.total_amount * Decimal("0.10")
def bulk_item_discount_strategy(order: Order) -> Decimal:
if order.item_count >= 10:
return order.total_amount * Decimal("0.15")
return Decimal("0.00")
--- 策略路由:基于 Python 3.10 Structural Pattern Matching ---
def resolve_strategy(order: Order) -> DiscountStrategy:
"""根据订单特征,匹配最优策略"""
match order:
case Order(user_tier="svip"):
嵌套/高阶策略组合
return lambda o: o.total_amount * Decimal("0.25")
case Order(user_tier="vip"):
return vip_discount_strategy
case Order(item_count=count) if count >= 10:
return bulk_item_discount_strategy
case _:
return no_discount_strategy
--- 业务上下文 ---
class ShoppingCart:
def init(self, order: Order, strategy: DiscountStrategy | None = None) -> None:
self.order = order
若未显示注入策略,则根据策略匹配引擎自动解析
self._strategy = strategy or resolve_strategy(order)
def calculate_final_price(self) -> Decimal:
discount = self._strategy(self.order)
return max(Decimal("0.00"), self.order.total_amount - discount)
--- 客户端调用 ---
if name == "main":
order_svip = Order(user_tier="svip", total_amount=Decimal("1000.00"), item_count=2)
cart1 = ShoppingCart(order_svip)
print(f"SVIP 结算价: {cart1.calculate_final_price()}") # 750.00
order_bulk = Order(user_tier="regular", total_amount=Decimal("500.00"), item_count=12)
cart2 = ShoppingCart(order_bulk)
print(f"批量购买结算价: {cart2.calculate_final_price()}") # 425.00
💡 核心演进要点:
* 去类化(Classless):策略本身就是函数,避免实例化无状态对象,大幅降低 GC 开销。
* 类型安全:使用 TypeAlias 与 Callable 明确定义策略签名,静态类型检查工具(如 Pyright/Mypy)可精确捕捉类型不匹配。
* 模式匹配路由:利用 Python 3.10 match-case 替代深层 if-elif-else 结构,使策略的选择规则更加清晰直观。
二、 责任链模式:从双向链表到生成器与管线函数
- 传统责任链模式的"痛点"
传统责任链依靠 Handler 内部持有 next_handler 引用,构建一条显式链表。缺点显而易见:
* 容易形成嵌套调用栈,导致调试跟踪困难(RecursionError 隐患)。
* 处理节点的组合与拆卸灵活性差,无法顺畅融入函数式数据流。
- Modern Python (3.10+) 演进方案:生成器管道与 Iterable 链
借助 Python 的 Protocol 与 中间件/管道流(Pipeline) 哲学,我们可以将责任链看作一组高阶函数组成的序列,或通过 match-case 统一派发。
重构方案:HTTP 请求安全校验流水线
from typing import Protocol, TypeAlias
from dataclasses import dataclass
from collections.abc import Iterable
@dataclass(slots=True)
class Request:
ip: str
token: str | None
payload: dict
is_authenticated: bool = False
is_rate_limited: bool = False
使用 Protocol 定义抽象处理逻辑,无需强制继承
class RequestHandler(Protocol):
def call(self, request: Request) -> Request | None:
"""
处理请求。
返回 Request 表示传递给下一个节点;返回 None 表示阻断链条。
"""
...
--- 节点定义(纯函数即可满足需求) ---
def rate_limit_middleware(request: Request) -> Request | None:
blacklisted_ips = {"192.168.1.100", "10.0.0.1"}
if request.ip in blacklisted_ips:
print(f"拒绝 IP {request.ip} 触发限流/黑名单。")
request.is_rate_limited = True
return None # 中断责任链
return request
def auth_middleware(request: Request) -> Request | None:
match request.token:
case str(tok) if tok.startswith("Bearer valid_"):
request.is_authenticated = True
return request
case _:
print("拒绝 身份验证 Failure: Token 无效。")
return None # 中断责任链
def sanitize_payload_middleware(request: Request) -> Request | None:
清洗请求 payload 中的潜在风险字段
if "script" in request.payload.get("data", ""):
print("警告 检测到 XSS 注入,字段已被清洗。")
request.payload"data" = request.payload"data".replace("script", "")
return request
--- 责任链管线构建器 ---
class Pipeline:
"""现代责任链容器:支持链式调用与高阶函数组合"""
def init(self, handlers: IterableRequestHandler | None = None) -> None:
self._handlers: listRequestHandler = list(handlers) if handlers else \[\]
def add_handler(self, handler: RequestHandler) -> "Pipeline":
self._handlers.append(handler)
return self
def process(self, request: Request) -> Request | None:
current_req: Request | None = request
for handler in self._handlers:
if current_req is None:
break
current_req = handler(current_req)
return current_req
--- 客户端调用 ---
if name == "main":
构建执行链
pipeline = (
Pipeline()
.add_handler(rate_limit_middleware)
.add_handler(auth_middleware)
.add_handler(sanitize_payload_middleware)
)
print("--- 场景 1:正常请求 ---")
req1 = Request(ip="127.0.0.1", token="Bearer valid_12345", payload={"data": "hello"})
res1 = pipeline.process(req1)
print(f"处理结果: {res1}\n")
print("--- 场景 2:黑名单 IP 阻断 ---")
req2 = Request(ip="192.168.1.100", token="Bearer valid_12345", payload={})
res2 = pipeline.process(req2)
print(f"处理结果: {res2}\n")
💡 核心演进要点:
* 扁平化迭代(Iterative vs Recursive):采用 for 循环遍历 Handler 队列替代传统的递归 handler.next(),完全抹平调用栈过深的隐患。
* 鸭子类型与 Protocol:通过 Protocol 消除类层次依赖,任意符合 Callable\[Request, Request | None] 签名的普通函数、闭包或类方法均可无缝加入责任链。
* 组合优于继承:利用 Fluent API(链式 add_handler)构建管线,表达力更强,支持运行时动态配置。
三、 总结与对比分析
| 设计模式 | 传统 Python / OOP 风格 | Modern Python (3.10+) 重构方案 | 演进优势 |
|---|---|---|---|
| 策略模式 | 继承 ABC 抽象类,每一个策略编写一个独立子类 | Callable 策略函数 + 模式匹配(match-case) | 消除冗余类定义,借助函数式特性实现零成本策略切换与强类型约束 |
| 责任链模式 | 显式单链表(持有 next 指针),递归派发 | Protocol + 生成器/管道迭代容器(Pipeline) | 消除调用栈深度隐患,实现极高扩展性的中间件架构(类似 ASGI/WSGI 管道) |
结语
Python 设计模式的演进历史,本质上是从"模仿 Java 式强面向对象"向"融合函数式与动态语言特质"的蜕变。在 Modern Python 中:
* 能用纯函数和 Callable 解决的,尽量不要造无状态的类。
* 巧用 Python 3.10+ 的模式匹配(Structural Pattern Matching) 处理分流与逻辑派发。
* 善用 Protocol 与强类型标注 为灵活的函数式代码提供可靠的静态检查保障。