装饰器模式的核心价值是在不修改原始类的前提下实现流处理行为的叠加、组合与撤销,通过统一接口包装对象并增强其功能,支持多层嵌套与正交职责分离。

装饰器模式的核心价值,就是在不动原始类的前提下,让流处理行为可叠加、可组合、可撤销。它不靠继承,而是靠“包装”——用一个具备相同接口的装饰器对象,把原始流对象包起来,在调用前后插入新逻辑。
明确接口统一性是前提
所有参与装饰的类(原始流、抽象装饰器、具体装饰器)必须实现同一接口(如 InputStream 或自定义的 StreamProcessor)。这样客户端才能无感知地替换对象,比如把 FileInputStream 换成 BufferedInputStream,代码完全不用改。
- 接口定义了基础能力,比如
read()、close() - 具体组件(如
FileInputStream)只专注自身职责:从文件读字节 - 装饰器类也实现该接口,并持有被装饰对象的引用
装饰器要能转发并增强行为
每个具体装饰器不是重写全部逻辑,而是“先调用被包装对象的方法,再加自己的动作”,或“先做预处理,再委托,最后后置处理”。例如:
-
BufferedInputStream在read()前检查缓冲区是否有数据;没有就调用底层in.read()填充缓冲区,再返回 -
ChecksumInputStream在每次read()后更新校验和,不影响原始读取语义 - 你自定义的
LoggingInputStream可在每次读操作前后打印日志,不干扰数据流本身
支持多层嵌套,组合自由
装饰器可以层层包裹,形成行为链。顺序决定执行逻辑——越外层的装饰器越先执行前置逻辑、越晚执行后置逻辑。例如:
new LoggingInputStream(new ChecksumInputStream(new BufferedInputStream(new FileInputStream("data.txt"))))- 读数据时:先进
LoggingInputStream的前置日志 → 再进ChecksumInputStream的校验更新 → 再进BufferedInputStream的缓冲判断 → 最终落到FileInputStream - 关闭时则逆序执行:先关日志资源,再算最终校验,再清缓冲,最后关文件句柄
避免过度装饰带来的维护负担
虽然灵活,但每新增一种功能就要写一个装饰器类。若功能间高度耦合或存在大量交叉组合(比如“带缓存+带压缩+带加密”),建议评估是否需引入配置化或策略组合机制,而非硬编码多个 ConcreteDecoratorXxx。
- 优先为正交职责设计装饰器(如缓冲、日志、校验、编码转换)
- 避免一个装饰器同时干多件事(比如既缓存又压缩),否则违背单一职责,也降低复用性
- 必要时可用工厂或构建器封装常见组合,提升使用便利性











