装饰器模式 (Decorator Pattern)
概述
装饰器模式动态地给对象添加职责,不改变对象本身和外部接口。它提供了比继承更有弹性的替代方案来扩展功能。通过组合而不是继承,实现功能的灵活扩展。
核心原则:
- 组合优于继承: 使用组合而非继承来拓展功能
- 开闭原则: 对扩展开放,对修改关闭
- 单一职责: 每个装饰器只添加一个职责
- 透明性: 装饰器与被装饰对象有相同接口
与继承的根本区别:
继承方式: 装饰器方式:
Vehicle ┌─ Vehicle (接口)
├─ Car ├─ RealCar
├─ CarWithAC ├─ ACDecorator
├─ CarWithSunroof ├─ SunroofDecorator
├─ CarWithACAndSunroof ├─ CustomPaintDecorator
└─ ... └─ ...
爆炸式增长 灵活组合
6个完美的使用场景
1. Java IO流处理(最经典应用)
文件读写需要支持多种功能组合:压缩、加密、缓冲、编码转换等。不能为每个组合创建子类。
// ❌ 不使用装饰器:类爆炸
FileInputStream
BufferedFileInputStream
GzipFileInputStream
GzipBufferedFileInputStream
GzipBufferedEncryptedFileInputStream
// ... 无法维护的组合爆炸
// ✅ 使用装饰器:灵活组合
InputStream in = new FileInputStream("file.txt.gz");
in = new GZIPInputStream(in);
in = new BufferedInputStream(in);
in = new CipherInputStream(in, cipher);
in = new InputStreamReader(in, "UTF-8");
2. Web框架中的功能中间件
服务方法需要支持多个功能:日志、缓存、鉴权、事务、性能监控、参数验证。每个功能独立,可选组合。
// HTTP请求处理链
UserService service = new UserServiceImpl();
service = new CachingDecorator(service); // 添加缓存
service = new LoggingDecorator(service); // 添加日志
service = new AuthenticationDecorator(service); // 添加鉴权
service = new ValidationDecorator(service); // 添加验证
service = new TransactionDecorator(service); // 添加事务
3. GUI组件功能扩展
窗口需要支持多种特效和行为的自由组合:边框、阴影、滚动条、透明度、缩放动画。
Window
├─ BorderWindow(添加边框)
├─ ShadowWindow(添加阴影)
├─ ScrollableWindow(添加滚动)
└─ 可以组合任意组合
4. 数据处理管道
数据需要经过多个处理步骤的自由组合:验证、转换、加密、压缩、序列化。
DataProcessor processor = new RawDataProcessor();
processor = new ValidationDecorator(processor);
processor = new TransformationDecorator(processor);
processor = new EncryptionDecorator(processor);
processor = new CompressionDecorator(processor);
5. 咖啡订单系统(教科书例子)
基础咖啡可选添加配料:牛奶、糖、巧克力、肉桂等。价格和描述动态变化。
Coffee coffee = new SimpleCoffee(); // $2.0
coffee = new MilkDecorator(coffee); // +$0.5 → $2.5
coffee = new SugarDecorator(coffee); // +$0.3 → $2.8
coffee = new ChocolateDecorator(coffee); // +$0.7 → $3.5
6. 数据库连接池和连接包装
物理连接需要添加透明的功能:连接验证、性能监控、慢查询日志、自动重连。
Connection physicalConn = DriverManager.getConnection(url);
Connection conn = new MonitoringDecorator(physicalConn);
conn = new PooledConnectionDecorator(conn);
conn = new LoggingDecorator(conn);
conn = new TimeoutDecorator(conn);
4个实现方法对比
| 方法 | 适用场景 | 优点 | 缺点 | 选择指数 |
|---|---|---|---|---|
| 继承式装饰器 | 规范工程 | 类型安全 | 代码多 | ⭐⭐⭐⭐ |
| 泛型装饰器 | 通用场景 | 通用性强 | 类型检查复杂 | ⭐⭐⭐⭐⭐ |
| 函数式装饰器 | 简单场景 | 代码简洁 | 难以复用 | ⭐⭐⭐ |
| 动态代理 | AOP场景 | 完全透明 | 性能开销 | ⭐⭐⭐ |
方法1: 继承式装饰器(标准实现)
// 基础接口
public interface DataStream {
String read();
void write(String data);
}
// 具体实现
public class FileDataStream implements DataStream {
@Override
public String read() {
return "File data";
}
@Override
public void write(String data) {
System.out.println("Writing to file: " + data);
}
}
// 抽象装饰器
public abstract class DataStreamDecorator implements DataStream {
protected DataStream wrappedStream;
protected DataStreamDecorator(DataStream stream) {
this.wrappedStream = stream;
}
}
// 具体装饰器1:压缩
public class CompressionDecorator extends DataStreamDecorator {
public CompressionDecorator(DataStream stream) {
super(stream);
}
@Override
public String read() {
String data = wrappedStream.read();
return decompress(data); // 解压
}
@Override
public void write(String data) {
String compressed = compress(data);
wrappedStream.write(compressed);
}
private String compress(String data) { return "compressed(" + data + ")"; }
private String decompress(String data) { return "decompressed(" + data + ")"; }
}
// 具体装饰器2:加密
public class EncryptionDecorator extends DataStreamDecorator {
public EncryptionDecorator(DataStream stream) {
super(stream);
}
@Override
public String read() {
String data = wrappedStream.read();
return decrypt(data);
}
@Override
public void write(String data) {
String encrypted = encrypt(data);
wrappedStream.write(encrypted);
}
private String encrypt(String data) { return "encrypted(" + data + ")"; }
private String decrypt(String data) { return "decrypted(" + data + ")"; }
}
// 具体装饰器3:缓冲
public class BufferingDecorator extends DataStreamDecorator {
private List<String> buffer = new ArrayList<>();
private static final int BUFFER_SIZE = 1024;
public BufferingDecorator(DataStream stream) {
super(stream);
}
@Override
public String read() {
// 缓冲读取逻辑
return wrappedStream.read();
}
@Override
public void write(String data) {
buffer.add(data);
if (buffer.size() >= BUFFER_SIZE) {
flush();
}
}
public void flush() {
buffer.forEach(wrappedStream::write);
buffer.clear();
}
}
// 使用示例
DataStream stream = new FileDataStream();
stream = new CompressionDecorator(stream);
stream = new EncryptionDecorator(stream);
stream = new BufferingDecorator(stream);
stream.write("Hello World"); // 自动压缩→加密→缓冲
String data = stream.read(); // 自动解缓冲→解密→解压
方法2: 泛型装饰器(通用性最强)
// 泛型装饰器,支持任何类型
public abstract class GenericDecorator<T> {
protected T wrapped;
protected GenericDecorator(T wrapped) {
this.wrapped = wrapped;
}
// 子类可以灵活拦截任何方法
}
// 日志装饰器
public class LoggingDecorator<T> implements InvocationHandler {
private T target;
public LoggingDecorator(T target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("[LOG] Calling: " + method.getName());
try {
Object result = method.invoke(target, args);
System.out.println("[LOG] Success: " + method.getName());
return result;
} catch (Exception e) {
System.out.println("[LOG] Failed: " + method.getName());
throw e;
} finally {
long duration = System.currentTimeMillis() - startTime;
System.out.println("[LOG] Duration: " + duration + "ms");
}
}
@SuppressWarnings("unchecked")
public <I> I decorate(Class<I> interfaceClass) {
return (I) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class[]{interfaceClass},
this
);
}
}
// 使用示例(可装饰任何接口)
UserService originalService = new UserServiceImpl();
LoggingDecorator<UserService> decorator = new LoggingDecorator<>(originalService);
UserService loggingService = decorator.decorate(UserService.class);
loggingService.getUser(123); // 自动记录日志
方法3: 函数式装饰器(Java 8+)
// 使用函数式接口
@FunctionalInterface
public interface Processor<T> {
T process(T input);
}
// 装饰器工厂
public class FunctionalDecorators {
// 日志装饰器
public static <T> Processor<T> withLogging(Processor<T> processor) {
return input -> {
System.out.println("Processing: " + input);
T result = processor.process(input);
System.out.println("Result: " + result);
return result;
};
}
// 缓存装饰器
public static <T> Processor<T> withCaching(Processor<T> processor) {
Map<T, T> cache = new ConcurrentHashMap<>();
return input -> cache.computeIfAbsent(input, k -> processor.process(k));
}
// 性能监控装饰器
public static <T> Processor<T> withProfiling(Processor<T> processor) {
return input -> {
long start = System.currentTimeMillis();
T result = processor.process(input);
long duration = System.currentTimeMillis() - start;
System.out.println("Execution time: " + duration + "ms");
return result;
};
}
}
// 使用示例
Processor<Integer> processor = x -> x * 2;
processor = FunctionalDecorators.withLogging(processor);
processor = FunctionalDecorators.withCaching(processor);
processor = FunctionalDecorators.withProfiling(processor);
Integer result = processor.process(5); // 链式调用所有装饰器
方法4: 动态代理装饰(AOP风格)
// 需要JDK动态代理或CGLIB
public class DecoratorProxy {
public static <T> T decorate(T target, Class<T> interfaceClass,
List<Interceptor> interceptors) {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class[]{interfaceClass},
(proxy, method, args) -> {
InterceptionChain chain = new InterceptionChain(method, target, interceptors);
return chain.proceed(args);
}
);
}
}
public interface Interceptor {
Object intercept(Method method, Object[] args, InterceptionChain chain) throws Throwable;
}
// 使用示例
UserService service = new UserServiceImpl();
List<Interceptor> interceptors = Arrays.asList(
new LoggingInterceptor(),
new CachingInterceptor(),
new PerformanceMonitorInterceptor()
);
UserService decoratedService = DecoratorProxy.decorate(service, UserService.class, interceptors);
4个常见问题 + 完整解决方案
问题1: 装饰器顺序问题 (Order Matters)
症状: 不同顺序的装饰导致结果完全不同,且很难发现
// ❌ 问题代码:顺序导致结果不一致
InputStream in1 = new FileInputStream("file.txt.gz");
in1 = new GZIPInputStream(in1); // 先解压
in1 = new BufferedInputStream(in1); // 再缓冲
// vs
InputStream in2 = new FileInputStream("file.txt.gz");
in2 = new BufferedInputStream(in2); // 先缓冲
in2 = new GZIPInputStream(in2); // 再解压
// in1和in2处理的数据不同!
// ✅ 解决方案1:记录装饰顺序
public class DecoratorChain<T> {
private T target;
private List<String> decorators = new ArrayList<>();
public DecoratorChain(T target) {
this.target = target;
}
public <D extends T> DecoratorChain<T> addDecorator(Class<D> decoratorClass) {
decorators.add(decoratorClass.getSimpleName());
return this;
}
public void printChain() {
System.out.println("Decoration order: " + decorators);
}
}
// ✅ 解决方案2:提供预定义的装饰器组合
public class DataStreamBuilder {
private InputStream in;
public DataStreamBuilder(InputStream in) {
this.in = in;
}
public DataStreamBuilder withCompression() {
try {
in = new GZIPInputStream(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
return this;
}
public DataStreamBuilder withBuffering() {
in = new BufferedInputStream(in);
return this;
}
public DataStreamBuilder withEncryption(Cipher cipher) {
in = new CipherInputStream(in, cipher);
return this;
}
// 正确的顺序:数据流→解压缩→解密→缓冲(解码)
public InputStream buildForDecryption() {
return withCompression()
.withEncryption(null) // 伪代码
.withBuffering()
.get();
}
public InputStream get() {
return in;
}
}
问题2: 装饰器与被装饰对象接口签名不匹配
症状: 装饰器添加了新方法,破坏了与原接口的一致性
// ❌ 问题代码:装饰器有额外方法
public class CachedUserService extends UserService { // 继承而非实现接口
@Override
public User getUser(int id) {
// 缓存逻辑
}
// 额外方法,破坏接口一致性
public void clearCache() { }
public Cache getCache() { }
}
// ✅ 解决方案:使用适配器模式或严格遵循接口
public interface UserService {
User getUser(int id);
// ... 其他方法
}
public class CachedUserServiceDecorator implements UserService {
private UserService wrapped;
private Cache cache;
public CachedUserServiceDecorator(UserService wrapped, Cache cache) {
this.wrapped = wrapped;
this.cache = cache;
}
@Override
public User getUser(int id) {
User cached = cache.get(id);
if (cached != null) return cached;
User user = wrapped.getUser(id);
cache.put(id, user);
return user;
}
// 如需额外功能,提供独立方法
public void clearCache() {
if (cache instanceof Clearable) {
((Clearable) cache).clear();
}
}
}
问题3: 多层装饰导致性能问题和调试困难
症状: 8层装饰导致进程变得极其缓慢,且栈跟踪极深
// ❌ 问题代码:过度装饰
service = new LoggingDecorator(service);
service = new CachingDecorator(service);
service = new ValidationDecorator(service);
service = new TransactionDecorator(service);
service = new PerformanceMonitorDecorator(service);
service = new SecurityDecorator(service);
service = new AuditingDecorator(service);
service = new CircuitBreakerDecorator(service); // 8层深度
// ✅ 解决方案1:限制装饰深度
public class DecoratorDepthValidator {
private static final int MAX_DEPTH = 3;
public static <T> void validate(T decorated) {
int depth = calculateDepth(decorated);
if (depth > MAX_DEPTH) {
throw new IllegalArgumentException(
"Decorator depth " + depth + " exceeds maximum " + MAX_DEPTH
);
}
}
private static <T> int calculateDepth(T obj) {
int depth = 0;
Object current = obj;
while (current instanceof Decorator) {
depth++;
current = ((Decorator) current).getWrapped();
}
return depth;
}
}
// ✅ 解决方案2:组合装饰器合并功能
public class ComprehensiveServiceDecorator implements UserService {
private UserService wrapped;
private Cache cache;
private PerformanceMonitor monitor;
private AuditLog auditLog;
public ComprehensiveServiceDecorator(UserService wrapped) {
this.wrapped = wrapped;
this.cache = new Cache();
this.monitor = new PerformanceMonitor();
this.auditLog = new AuditLog();
}
@Override
public User getUser(int id) {
long startTime = System.currentTimeMillis();
try {
// 缓存检查
User cached = cache.get(id);
if (cached != null) {
auditLog.log("Cache hit for user " + id);
return cached;
}
// 执行
User user = wrapped.getUser(id);
cache.put(id, user);
// 审计
auditLog.log("Fetched user " + id);
return user;
} finally {
// 性能监控
long duration = System.currentTimeMillis() - startTime;
monitor.record("getUser", duration);
}
}
}
问题4: 装饰器链中异常处理不当
症状: 某个装饰器抛异常,导致整个链失败或失败模式不明确
// ❌ 问题代码:异常处理不当
public String process(String data) {
data = compressionDecorator.process(data); // 可能失败
data = encryptionDecorator.process(data); // 可能失败
data = validationDecorator.process(data); // 可能失败
return data; // 如果中间失败,状态不清
}
// ✅ 解决方案:完善的异常处理和恢复
public class ResilientDecoratorChain {
private List<SafeDecorator> decorators = new ArrayList<>();
private ErrorHandler errorHandler;
public ResilientDecoratorChain(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public Result process(Input input) {
Result current = new Result(input);
for (int i = 0; i < decorators.size(); i++) {
try {
current = decorators.get(i).decorate(current);
} catch (Exception e) {
// 记录失败点
errorHandler.handle(input, i, decorators.get(i), e);
// 决定是否继续
if (errorHandler.shouldContinue(e)) {
// 跳过此装饰器,继续下一个
continue;
} else if (errorHandler.shouldRetry(e)) {
// 重试此装饰器
i--;
continue;
} else {
// 中止处理,返回失败状态
return Result.failure(e);
}
}
}
return current;
}
}
最佳实践指南
1️⃣ 装饰器职责要专一
// ❌ 一个装饰器做太多事
public class MegaDecorator extends DataStream {
@Override
public String read() {
// 压缩、加密、日志、缓存、性能监控全部在这里
}
}
// ✅ 各司其职
public class CompressionDecorator extends DataStream {
@Override
public String read() {
return decompress(wrapped.read());
}
}
public class LoggingDecorator extends DataStream {
@Override
public String read() {
System.out.println("Reading...");
return wrapped.read();
}
}
2️⃣ 使用Builder模式简化装饰链构建
// ✅ Builder模式
public class DataStreamBuilder {
private InputStream stream;
public DataStreamBuilder(InputStream stream) {
this.stream = stream;
}
public DataStreamBuilder compress() {
stream = new CompressionDecorator(stream);
return this;
}
public DataStreamBuilder encrypt(Cipher cipher) {
stream = new EncryptionDecorator(stream, cipher);
return this;
}
public DataStreamBuilder buffer() {
stream = new BufferingDecorator(stream);
return this;
}
public InputStream build() {
return stream;
}
}
// 使用
InputStream in = new DataStreamBuilder(
new FileInputStream("data.bin")
)
.compress()
.encrypt(cipher)
.buffer()
.build();
3️⃣ 提供清晰的装饰器文档
/**
* 缓存装饰器
*
* 作用: 缓存方法调用结果
*
* 使用场景:
* - 方法调用结果稳定且获取开销大
* - 可以接受短时间的数据延迟
*
* 顺序建议:
* - 应该在日志装饰器之后(避免记录缓存命中)
* - 应该在数据转换装饰器之前(缓存转换后的结果)
*
* 性能影响:
* - 首次调用: +20% 开销(缓存存储)
* - 缓存命中: -80% 开销(直接返回)
* - 内存: +N * (key_size + value_size)
*
* @param <T> 被装饰对象类型
*/
public class CachingDecorator<T> extends Decorator<T> {
// 实现...
}
4️⃣ 支持装饰器的反思和诊断
public interface Decorator<T> {
T getWrapped();
String getDecoratorName();
int getDecoratorDepth();
}
public class DecoratorDiagnostics {
public static <T> void printChain(T decorated) {
System.out.println("Decorator Chain:");
Object current = decorated;
int level = 0;
while (current instanceof Decorator) {
Decorator<?> decorator = (Decorator<?>) current;
System.out.println(
" " + level + ". " + decorator.getDecoratorName()
);
current = decorator.getWrapped();
level++;
}
System.out.println(" " + level + ". " + current.getClass().getSimpleName() + " (core)");
}
}
5️⃣ 支持装饰器的动态移除和替换
public class RemovableDecorator<T> implements Decorator<T> {
private T wrapped;
private String name;
public RemovableDecorator(T wrapped, String name) {
this.wrapped = wrapped;
this.name = name;
}
@Override
public T getWrapped() {
return wrapped; // 支持剥离此装饰器
}
public T unwrap() {
return wrapped; // 移除自己,返回被包装的对象
}
}
// 使用示例
UserService service = originalService;
service = new LoggingDecorator(service);
service = new CachingDecorator(service);
service = new ValidationDecorator(service);
// 如需移除缓存装饰
if (service instanceof RemovableDecorator) {
RemovableDecorator<?> removable = (RemovableDecorator<?>) service;
service = (UserService) removable.unwrap(); // 恢复到去掉缓存前的状态
}
与其他模式的关系
| 相关模式 | 关系 | 何时选择 |
|---|---|---|
| Strategy | 都改变对象行为,但Strategy是替换算法,Decorator是添加功能 | 需要替换→Strategy;需要扩展→Decorator |
| Proxy | 都包装对象,但Proxy通常是一对一,Decorator支持多层 | 需要访问控制→Proxy;需要功能组合→Decorator |
| Adapter | 都改变接口,但Adapter改变不兼容接口,Decorator保持不变 | 接口不匹配→Adapter;功能扩展→Decorator |
| Builder | 都实现灵活的对象构建,Decorator运行时动态,Builder是构造时静态 | 构造时灵活→Builder;运行时灵活→Decorator |
| Composite | 都支持递归组合,但Composite处理树结构,Decorator是线性链 | 树形结构→Composite;链式功能→Decorator |
多语言实现考量
Java特性应用
- 使用
extends + implements支持多接口装饰 - 利用
@Delegate注解(Lombok)自动转发方法 - Java IO是装饰器模式的标准库示范
Python考量
- Python的鸭子类型使装饰器更灵活
- 支持
@property和属性转发 - 函数装饰器(
@decorator)比类装饰器更常见
TypeScript/JavaScript考量
- 支持高阶函数,函数装饰器自然
- 装饰器提案(
@decorator)语言原生支持 - 动态属性访问(Proxy对象)更强大
何时避免使用
- ❌ 只需要简单继承: 类层级不复杂,功能组合不多
- ❌ 性能极其关键: 多层装饰的调用链开销不可接受
- ❌ 接口频繁变化: 装饰器维护成本超过继承
- ❌ 装饰顺序复杂: 顺序依赖导致难以维护
- ❌ 单个装饰器过于复杂: 应该考虑策略模式或责任链