Python 进阶:重构经典设计模式(四)—— 策略模式与责任链模式在 Python 3.10+ 中的函数式与解耦演进

> 前言:在前面的章节中,我们重构了工厂与观察者模式。在设计模式的"行为型"家族中,策略模式(Strategy Pattern) 与 责任链模式(Chain of Responsibility Pattern) 常常充斥着大量的类继承、接口定义与繁琐的上下文切换。

> 随着 Python 3.10+ 引入 强化的模式匹配(Pattern Matching)、Callable 类型约束 以及 可空/联合类型语法(|),我们完全可以用面向函数(Functional Approach)和轻量级协议(Protocol)对这两个经典模式进行彻头彻尾的重构。

>

一、 策略模式:从 OOP 冗余到函数式一等公民

  1. 传统策略模式的"痛点"

在传统的 Java/C++ 式 OOP 编写方式中,策略模式通常需要:

* 定义一个抽象策略基类(或接口)。

* 为每一种具体算法(策略)继承并实现一个 StrategyClass。

* 定义一个 Context 上下文类来持有策略实例。

这种写法在 Python 中显得过于笨重,且创建了大量的无状态对象。

  1. 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 结构,使策略的选择规则更加清晰直观。

二、 责任链模式:从双向链表到生成器与管线函数

  1. 传统责任链模式的"痛点"

传统责任链依靠 Handler 内部持有 next_handler 引用,构建一条显式链表。缺点显而易见:

* 容易形成嵌套调用栈,导致调试跟踪困难(RecursionError 隐患)。

* 处理节点的组合与拆卸灵活性差,无法顺畅融入函数式数据流。

  1. 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 与强类型标注 为灵活的函数式代码提供可靠的静态检查保障。

相关推荐
打工仔折腾 AI1 小时前
数据库上 K8s 之后谁来管?拆解金仓 KES-Operator 的声明式运维方案
人工智能·后端·python·性能优化·ai agent 实战
QXWZ_IA1 小时前
道路巡检高危作业的自动化替代方案
人工智能·科技·安全
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】SQLite基础概念与C的API开发
网络·c++·人工智能·学习·架构
Hotchip_MEMS1 小时前
平板MEMS麦克风阵列如何赋能远程会议与远场拾音
人工智能·笔记·物联网·电脑·制造
正经教主1 小时前
【FDE系列】阶段2:Day 33:进阶查询 — 窗口函数与 CTE
人工智能·python·fde
张彦峰ZYF1 小时前
AI时代Java工程师能力地图:哪些会被替代,哪些更加值钱
人工智能·架构·被替代的不是岗位而是任务·生成成本塌陷,验证成本没降·上下文闭合度·可判定性、可逆性·责任可归属性
棣廷1 小时前
初识OpenCV——疲劳检测
人工智能·opencv·目标检测
byte轻骑兵1 小时前
【BlueZ 】Linux 内核蓝牙子系统入门:hci_core 模块与 BlueZ 的交互
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
Dr_Fourier1 小时前
AWQ量化
c++·人工智能·pytorch·ai