问题背景:促销策略的重复陷阱
在电商促销系统中,我们曾面临这样的痛点:
python
promos = [fidelity_promo, bulk_item_promo, large_order_promo] # 6.1节原始方案
def best_promo(order):
return max(promo(order) for promo in promos)
当新增new_promo时,开发者可能忘记将其加入promos列表,导致策略失效且无报错。这种隐性缺陷会引发严重业务问题。
装饰器解决方案:自动化策略注册
通过@promotion装饰器实现策略自动注册,代码结构如下:
python
promos = [] # ❶ 策略容器
def promotion(promo_func): # ❷ 装饰器工厂
promos.append(promo_func)
return promo_func
@promotion # ❸ 自动注册
def fidelity(order):
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
# 其他策略同理...
核心机制:
promotion
装饰器将函数添加到promos
列表best_promo
直接依赖动态更新的promos
列表- 新增策略只需添加
@promotion
注解
方案优势深度解析
命名自由化
- 旧方案 :
fidelity_promo
等强制后缀 - 新方案 :
fidelity
等语义化命名
python
# 旧写法 vs 新写法
def fidelity_promo(order): ... # 旧
@promotion
def fidelity(order): ... # 新
策略启用/禁用便捷
python
# 临时禁用大额订单折扣
# @promotion
def large_order(order): ... # 注释装饰器即可
模块化扩展
python
# 在其他模块中定义策略
from .promotion import promotion
@promotion
def seasonal(order): # 节日促销策略
return order.total() * .2 if is_holiday() else 0
闭包与作用域揭秘
装饰器的魔法源于闭包机制:
python
def outer():
data = []
def inner(func):
data.append(func)
return func
return inner
# 等价于:
promotion = outer()
@promotion
def strategy(): ...
关键点:
promos
列表作为闭包变量被装饰器捕获- 每个装饰器调用独立维护策略集合(需注意多文件场景)
实践建议
- 装饰器集中管理 :将
promotion
定义在独立模块 - 异常处理 :为促销函数添加
try-except
- 缓存优化:对高频计算结果进行缓存
- 版本控制:通过装饰器参数管理策略版本
python
def promotion(version=1):
def decorator(func):
promos[version].append(func)
return func
return decorator
@promotion(2) # 新版本策略
def bulk_item(order): ...
总结
通过装饰器模式,我们实现了:
✅ 策略注册自动化
✅ 系统扩展零成本
✅ 业务逻辑高内聚
✅ 维护成本指数级下降
这种设计思想不仅适用于促销系统,还可延伸至权限控制、日志记录等场景。理解闭包与作用域机制,是掌握高级Python设计模式的关键。