装饰器模式是通过组合包装在运行时叠加行为,核心在于构造时传入被装饰对象以确立调用链,各层独立管理状态、遵循接口一致性、显式委托且禁止static共享。
装饰器模式不是“加个注解就完事”,而是通过组合包装,在运行时一层层叠加行为。关键不在语法糖,而在如何让每层装饰既独立、又可控、还能安全嵌套。
核心变量技巧:装饰链的控制权在构造阶段
所有装饰器必须接收被装饰对象作为参数,这个引用就是功能链的起点。它决定了行为执行顺序和数据流向——最外层装饰器最先响应调用,最终委托到底层具体组件。
- 不要在装饰器内部 new 具体实现类,否则破坏依赖倒置;应由上层统一创建并传入
- 多个装饰器嵌套时,顺序即逻辑顺序:new AuthDecorator(new CacheDecorator(new ApiService())) 表示先鉴权、再查缓存、最后调用服务
- 若某层需中断流程(如权限拒绝),直接 return 或抛异常,不调用 _inner.xxx() 即可切断链条
状态变量要隔离,避免跨层污染
每个装饰器应管理自己的状态,不能共享或误用其他装饰器的字段。比如日志装饰器记录耗时,缓存装饰器维护字典,二者互不感知。
- 缓存装饰器需自己声明 private readonly Dictionary
_cache = new() - 重试装饰器要持有重试次数、间隔策略等私有字段,不依赖外部传参或静态变量
- 禁止用 static 字段存上下文——多线程下会串话;改用方法参数或装饰器实例字段传递必要信息
接口一致性是装饰生效的前提
所有具体组件与装饰器必须实现同一接口。这不是形式要求,而是类型系统保障“替换透明性”的基础——客户端代码完全感知不到是否被装饰过。
- 接口方法签名必须严格一致,包括返回类型、参数名(尤其强类型语言如 C#、Java)
- 若原始组件有 Dispose、Async 方法,装饰器也需实现对应逻辑,并正确委托或增强
- 泛型接口(如 IHandler
)可复用装饰逻辑,但要注意约束条件和协变/逆变支持
调试友好性靠显式委托,而非隐式代理
装饰器里每一处对 _inner 的调用都应清晰可见。这既是可读性的需要,也是排查链断裂、无限递归等问题的关键。
- 避免 this.Method() 代替 _inner.Method() —— 极易引发栈溢出
- 建议在关键委托点添加轻量日志,例如 “→ entering LoggingDecorator.Read()” 和 “← exiting with result”
- 单元测试时可传入 Mock 组件,验证装饰器是否在正确时机调用 _inner 并处理返回值/异常










