装饰器模式通过包装而非继承,在不修改原始类代码的前提下动态叠加行为;所有类实现统一接口,装饰器持有被装饰对象并转发调用,支持运行时灵活组合与无缝嵌套。

装饰器模式的核心,是在不改动原始类代码的前提下,通过包装(wrap)的方式,一层层叠加新行为。它不是靠继承硬编码功能,而是运行时灵活组合,让对象“穿衣服”而不是“换身体”。
明确统一接口,是装饰的前提
所有参与装饰的类——原始对象、装饰器基类、具体装饰器——都必须实现同一个抽象接口。比如定义一个 Coffee 接口,只规定 cost() 方法;SimpleCoffee 实现基础价格,CoffeeDecorator 持有 Coffee 引用并转发调用;后续的 MilkDecorator、SugarDecorator 就在此基础上加钱。接口一致,才能无缝替换和嵌套。
装饰器持有被装饰对象,不是继承它
每个装饰器类内部保存一个组件实例(如 self._coffee),在自己的方法中显式调用该实例的方法。这样既复用了原逻辑,又能在调用前或后插入新动作。例如 TimeLog 装饰器先打印时间,再调用 self.log.error();LevelLog 先输出级别,再执行原始日志。这种组合关系比继承更松耦合,也避免了子类爆炸。
运行时动态组装,按需叠加
- 创建基础对象:coffee = SimpleCoffee()
- 逐层包装:coffee = MilkDecorator(coffee) → coffee = SugarDecorator(coffee)
- 最终调用:coffee.cost() 会依次触发糖、奶、基础咖啡的计价逻辑
你不需要提前定义 MilkSugarCoffee 这种类,也不用改任何已有代码。新增一种配料?写一个新的装饰器类,然后在创建时加上就行。
注意保持元信息与调用一致性
如果是用 Python 函数装饰器增强方法,记得用 @functools.wraps(func) 保留原函数的 __name__、__doc__ 等属性,否则调试和反射会出问题。对类装饰器或手动包装场景,则要确保装饰器方法签名与被装饰接口完全一致,参数和返回值类型不破坏契约。


















