跳到主要内容

装饰器模式

问题

什么是装饰器模式?与继承有什么区别?Java 中有哪些典型应用?

答案

核心思想

在不修改原对象的前提下,动态地给对象添加新功能。通过组合(持有原对象引用)而非继承来扩展功能,支持多层装饰叠加。

装饰器 vs 继承

维度装饰器模式继承
扩展方式运行时动态组合编译时静态确定
灵活性可任意组合装饰每种组合需要一个子类
类数量少(N 个装饰器)多(组合爆炸 2^N)

实现示例

装饰器模式 - 数据流处理
// 组件接口
public interface DataSource {
void writeData(String data);
String readData();
}

// 原始实现
public class FileDataSource implements DataSource {
private final String filename;

public FileDataSource(String filename) { this.filename = filename; }

@Override
public void writeData(String data) { /* 写文件 */ }
@Override
public String readData() { /* 读文件 */ return ""; }
}

// 装饰器基类:持有被装饰对象的引用
public abstract class DataSourceDecorator implements DataSource {
protected final DataSource wrappee;

public DataSourceDecorator(DataSource source) {
this.wrappee = source;
}

@Override
public void writeData(String data) { wrappee.writeData(data); }
@Override
public String readData() { return wrappee.readData(); }
}

// 加密装饰器
public class EncryptionDecorator extends DataSourceDecorator {
public EncryptionDecorator(DataSource source) { super(source); }

@Override
public void writeData(String data) {
super.writeData(encrypt(data)); // 先加密再写
}

@Override
public String readData() {
return decrypt(super.readData()); // 先读再解密
}
}

// 压缩装饰器
public class CompressionDecorator extends DataSourceDecorator {
public CompressionDecorator(DataSource source) { super(source); }

@Override
public void writeData(String data) {
super.writeData(compress(data)); // 先压缩再写
}
}

// 使用:自由组合装饰器
DataSource source = new FileDataSource("data.txt");
source = new EncryptionDecorator(source); // 加密
source = new CompressionDecorator(source); // 压缩
source.writeData("hello"); // 压缩 → 加密 → 写文件

Java IO 中的装饰器

Java IO 是装饰器模式最经典的应用。

Java IO 装饰器链
// FileInputStream → BufferedInputStream → DataInputStream
InputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("data.bin")
)
);

// 每一层都是装饰器,增加一项能力:
// FileInputStream:读文件
// BufferedInputStream:增加缓冲(减少磁盘 IO)
// DataInputStream:增加读取基本类型(readInt、readDouble)

常见面试问题

Q1: 装饰器模式和代理模式的区别?

答案

维度装饰器模式代理模式
目的增强功能(加缓冲、加加密)控制访问(权限、缓存、延迟加载)
叠加多层装饰器可以叠加通常只有一层代理
关注点增加新行为管理对目标对象的访问

Q2: Java IO 为什么用装饰器而不是继承?

答案

Java IO 有 4 种基础流(File、ByteArray、Piped、Socket)和多种增强功能(缓冲、数据类型、压缩、加密)。如果用继承,需要 4 × N 个子类(BufferedFileInputStream、BufferedSocketInputStream...),组合爆炸。

装饰器模式下,基础流和增强功能独立开发,通过组合自由搭配。

Q3: Spring 中的装饰器模式?

答案

  • HttpServletRequestWrapper:装饰 HttpServletRequest,自定义请求处理
  • TransactionAwareCacheDecorator:给缓存添加事务感知能力
  • BeanDefinitionDecorator:装饰 BeanDefinition

相关链接