装饰模式通过组合替代继承实现功能叠加,Mixin提供可复用能力,MRO需规范初始化,优先用组合表达“has-a”关系而非深层继承。

用装饰模式替代继承链叠加功能
当一个类反复被要求“加个高亮”“再加个日志”“还要支持缓存”,直接在原类里堆 if is_bold 或新增字段,很快就会变成300行+、28个测试用例、没人敢动第178行的怪物。这不是写代码,是在给类打补丁。
装饰模式的核心是:把每个新功能拆成独立类,它们都实现同一接口(比如 render()),然后一层套一层包装原始对象。不改原类,不新增分支,也不爆炸式新建子类。
- 原始类只负责核心逻辑(如纯文本渲染)
- 每个装饰器只做一件事(
HighlightDecorator只管颜色,TimingDecorator只管耗时统计) - 组合顺序即行为顺序:
TimingDecorator(HighlightDecorator(text_display))表示先高亮再计时
用Mixin类提取跨继承树的共用行为
当你发现 Mock1(Base) 和 Mock2(Derived) 都要写一模一样的 my_func,说明这不是“谁是谁”的关系,而是“谁都需要这个能力”。硬拉继承只会让类图越来越拧巴。
Mixin 是无状态、无构造依赖的轻量类,只提供方法,不定义完整对象语义。它不参与 MRO 主干,只作为能力插件混入:
立即学习“Python免费学习笔记(深入)”;
Python 编程规范与最佳实践。强制 PEP 8 代码风格、语法校验、单元测试执行,适用于代码编写、审查和重构。触发词:Python、代码规范、py_compile、单元测试。
- 定义
MyFuncMixin,里面只有my_func(self, for_val) -
Mock1(Base, MyFuncMixin)和Mock2(Derived, MyFuncMixin)同时获得该方法 - Mixin 类必须继承
object,且自身不定义__init__,或仅接受**kwargs并调用super().__init__(**kwargs)
检查 MRO 并统一用 super() 处理初始化
多继承下 __init__ 被执行两次、某个父类完全没初始化、或者 AttributeError 报在奇怪位置——大概率是 MRO 没理清,或有人偷偷写了 Parent.__init__(self)。
运行 ClassName.__mro__ 看实际顺序,再逐个确认每个类的 __init__ 是否都用 super().__init__(**kwargs):
- 哪怕是最顶层基类,也要接受
**kwargs,否则下游传参会中断 - 不要假设
super()一定调到“字面父类”,它只按__mro__列表往下找下一个有该方法的类 - 如果某个类没定义
__init__,super().__init__()会继续往下找,直到object—— 这是安全的,但容易掩盖遗漏
避免深层继承,优先用组合表达“has-a”关系
继承解决的是“is-a”,组合解决的是“has-a”。比如订单服务不是一种用户服务,但它可能需要一个 UserValidator 实例来校验用户权限。
把行为抽成独立对象,通过属性注入,比让 OrderService 去继承 UserService 更干净:
-
class OrderService:里面有个self.validator = UserValidator() - 需要扩展验证逻辑时,换一个符合接口的新 validator 即可,不用动
OrderService的继承结构 - 单元测试也更简单:mock 一个 validator 替换真实实现,边界清晰
真正难的不是写出能跑的继承树,而是每次加功能前,先问一句:这个新需求,真的需要改变类的身份(is-a),还是只要借用一段行为(has-a / can-do)?后者往往更轻、更稳、更容易测。

















