Skip to content

装饰器模式

装饰器模式用于在不修改原对象的情况下,动态增强对象能力。它通过“包装原对象”的方式,在调用前后增加额外逻辑。

为什么需要装饰器模式

假设一个文件读取器本来只负责读取内容,现在希望增加日志、缓冲、加密、统计耗时。如果直接改原类,会让原类越来越复杂。

mermaid
flowchart TD
    A["原始读取器"] --> B["读取文件"]
    A --> C["新增日志"]
    A --> D["新增缓冲"]
    A --> E["新增加密"]
    A --> F["统计耗时"]

问题:

  1. 原类职责变多。
  2. 不同增强组合很难复用。
  3. 新增强能力要修改老代码。

装饰器把增强逻辑拆成一层层包装:

mermaid
flowchart TD
    A["调用方"] --> B["日志装饰器"]
    B --> C["缓冲装饰器"]
    C --> D["文件读取器"]

基本结构

角色作用
Component原对象和装饰器共同实现的接口
ConcreteComponent原始对象
Decorator持有 Component 引用
ConcreteDecorator在调用前后增加功能

Java IO 示例

Java IO 大量使用装饰器模式。

java
InputStream input = new BufferedInputStream(
    new FileInputStream("demo.txt")
);

FileInputStream 负责读取文件,BufferedInputStream 增加缓冲能力。调用方看到的仍然是 InputStream

执行流程:

mermaid
flowchart TD
    A["调用 read"] --> B["BufferedInputStream"]
    B --> C{"缓冲区是否有数据"}
    C -- "有" --> D["直接返回"]
    C -- "没有" --> E["调用 FileInputStream"]
    E --> F["读取文件并填充缓冲区"]
    F --> D

代码 Demo

公共接口:

java
public interface DataSource {
    String read();
}

原始对象:

java
public class FileDataSource implements DataSource {
    @Override
    public String read() {
        return "file data";
    }
}

抽象装饰器:

java
public abstract class DataSourceDecorator implements DataSource {
    protected final DataSource target;

    protected DataSourceDecorator(DataSource target) {
        this.target = target;
    }
}

日志装饰器:

java
public class LogDataSourceDecorator extends DataSourceDecorator {
    public LogDataSourceDecorator(DataSource target) {
        super(target);
    }

    @Override
    public String read() {
        System.out.println("read start");
        String value = target.read();
        System.out.println("read end");
        return value;
    }
}

使用:

java
DataSource dataSource = new LogDataSourceDecorator(new FileDataSource());
String value = dataSource.read();

和代理模式区别

对比项装饰器模式代理模式
目的动态叠加功能控制访问或增强调用
关注点功能组合访问控制、远程代理、延迟加载、AOP
是否强调多层叠加不一定
典型例子Java IOSpring AOP、动态代理

结构上二者都可能“包一层”,但意图不同。装饰器强调增强能力可组合,代理强调控制访问。

滥用风险

风险后果
装饰层太多调用链很深,调试困难
装饰器改变原语义调用方预期被破坏
构造顺序不清楚不同包装顺序结果不同
简单增强也手写装饰器不如 AOP 或普通方法直观

小结

装饰器模式适合在不修改原类的情况下,为对象动态叠加能力。它的核心是“原对象和装饰器实现同一个接口”,调用方不需要知道自己拿到的是原始对象还是被增强后的对象。