# 装饰器模式:动态扩展功能的艺术

# 一、业务痛点与技术背景

核心价值:解决日志系统中动态添加日志格式、缓存系统中灵活组合缓存策略等实际问题,掌握装饰器模式在中间件开发中的最佳实践,避免继承爆炸和功能耦合问题。

在我们开发的分布式缓存系统中,最初只有基础的缓存功能。随着业务发展,需要添加统计监控、数据压缩、加密、限流等多种增强功能。如果使用继承方式,将会产生 2^n 个组合类(n 个功能点),维护成本呈指数级增长。

更严重的是,在一次系统升级中,由于继承层次过深,一个看似无害的修改导致了连锁反应,使得缓存系统的性能下降了 40%,直接影响了整个交易链路的响应时间。这次事故让我们深刻认识到:静态继承无法满足功能的动态组合需求

# 二、装饰器模式的核心原理

# 2.1 本质类比:俄罗斯套娃

装饰器模式的本质就像俄罗斯套娃

  • 最内层的娃娃:被装饰的原始对象(Component)
  • 外层的每个娃娃:装饰器(Decorator),为内层添加新功能
  • 整体外观:保持了娃娃的形状(接口一致性)

关键在于:每个娃娃都可以独立存在,也可以任意组合,这种层层包裹的方式实现了功能的动态叠加。

# 2.2 核心设计逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// 组件接口 - 定义核心功能
public interface CacheService {
/**
* 获取缓存值
* @param key 缓存键
* @return 缓存值
*/
Object get(String key);

/**
* 设置缓存值
* @param key 缓存键
* @param value 缓存值
* @param expireTime 过期时间
*/
void put(String key, Object value, long expireTime);

/**
* 删除缓存
* @param key 缓存键
*/
void delete(String key);

/**
* 获取组件名称
*/
String getComponentName();
}

// 具体组件 - 基础缓存实现
@Component
public class RedisCacheService implements CacheService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Override
public Object get(String key) {
try {
return redisTemplate.opsForValue().get(key);
} catch (Exception e) {
log.error("Redis获取缓存失败: key={}", key, e);
return null;
}
}

@Override
public void put(String key, Object value, long expireTime) {
try {
redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
} catch (Exception e) {
log.error("Redis设置缓存失败: key={}", key, e);
}
}

@Override
public void delete(String key) {
try {
redisTemplate.delete(key);
} catch (Exception e) {
log.error("Redis删除缓存失败: key={}", key, e);
}
}

@Override
public String getComponentName() {
return "RedisCache";
}
}

// 抽象装饰器 - 实现组件接口,持有组件引用
public abstract class CacheDecorator implements CacheService {
protected final CacheService cacheService;

public CacheDecorator(CacheService cacheService) {
this.cacheService = cacheService;
}

@Override
public Object get(String key) {
return cacheService.get(key);
}

@Override
public void put(String key, Object value, long expireTime) {
cacheService.put(key, value, expireTime);
}

@Override
public void delete(String key) {
cacheService.delete(key);
}

@Override
public String getComponentName() {
return cacheService.getComponentName();
}
}

// 具体装饰器 - 统计功能
@Component
public class StatisticsDecorator extends CacheDecorator {

private final MeterRegistry meterRegistry;
private final Timer.Sample sample;

public StatisticsDecorator(CacheService cacheService, MeterRegistry meterRegistry) {
super(cacheService);
this.meterRegistry = meterRegistry;
this.sample = Timer.start(meterRegistry);
}

@Override
public Object get(String key) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
Object result = super.get(key);

// 统计命中率
if (result != null) {
meterRegistry.counter("cache.hit", "component", getComponentName()).increment();
} else {
meterRegistry.counter("cache.miss", "component", getComponentName()).increment();
}

return result;
} finally {
sample.stop(Timer.builder("cache.get")
.tag("component", getComponentName())
.register(meterRegistry));
}
}

@Override
public void put(String key, Object value, long expireTime) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
super.put(key, value, expireTime);
meterRegistry.counter("cache.put", "component", getComponentName()).increment();
} finally {
sample.stop(Timer.builder("cache.put")
.tag("component", getComponentName())
.register(meterRegistry));
}
}

@Override
public String getComponentName() {
return "Statistics-" + super.getComponentName();
}
}

// 具体装饰器 - 压缩功能
@Component
public class CompressionDecorator extends CacheDecorator {

private final CompressionStrategy compressionStrategy;

public CompressionDecorator(CacheService cacheService, CompressionStrategy compressionStrategy) {
super(cacheService);
this.compressionStrategy = compressionStrategy;
}

@Override
public Object get(String key) {
Object compressedValue = super.get(key);
if (compressedValue instanceof byte[]) {
try {
return compressionStrategy.decompress((byte[]) compressedValue);
} catch (IOException e) {
log.error("解压缩失败: key={}", key, e);
return null;
}
}
return compressedValue;
}

@Override
public void put(String key, Object value, long expireTime) {
if (value instanceof Serializable) {
try {
byte[] compressedData = compressionStrategy.compress(value);
super.put(key, compressedData, expireTime);
} catch (IOException e) {
log.error("压缩失败: key={}", key, e);
// 降级处理:存储原始数据
super.put(key, value, expireTime);
}
} else {
super.put(key, value, expireTime);
}
}

@Override
public String getComponentName() {
return "Compression-" + super.getComponentName();
}
}

工程师洞察:装饰器模式的精妙之处在于透明性 —— 装饰器与被装饰对象实现相同的接口,客户端代码无需区分。这种设计使得功能的组合变得像搭积木一样简单。

# 三、实践方案:缓存系统功能增强

# 3.1 场景约束与设计思路

适用场景

  • 需要动态组合多种功能
  • 功能之间相对独立,没有强依赖关系
  • 需要在运行时决定功能组合
  • 避免继承层次的爆炸式增长

不适用场景

  • 功能之间有复杂的依赖关系
  • 需要频繁修改组件接口
  • 性能要求极高的场景(装饰器有调用开销)

# 3.2 具体实现步骤

第一步:装饰器工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Component
public class CacheDecoratorFactory {

private final ApplicationContext applicationContext;

public CacheDecoratorFactory(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}

public CacheService createCacheService(String... decoratorNames) {
// 创建基础缓存服务
CacheService cacheService = applicationContext.getBean(RedisCacheService.class);

// 按顺序应用装饰器
for (String decoratorName : decoratorNames) {
cacheService = createDecorator(cacheService, decoratorName);
}

return cacheService;
}

private CacheService createDecorator(CacheService cacheService, String decoratorName) {
switch (decoratorName.toLowerCase()) {
case "statistics":
return new StatisticsDecorator(cacheService, applicationContext.getBean(MeterRegistry.class));
case "compression":
return new CompressionDecorator(cacheService, applicationContext.getBean(CompressionStrategy.class));
case "encryption":
return new EncryptionDecorator(cacheService, applicationContext.getBean(EncryptionService.class));
case "ratelimit":
return new RateLimitDecorator(cacheService, applicationContext.getBean(RateLimiter.class));
default:
throw new IllegalArgumentException("未知的装饰器: " + decoratorName);
}
}
}

第二步:配置驱动的装饰器组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@ConfigurationProperties(prefix = "cache.decorators")
@Data
public class CacheDecoratorConfig {
private List<String> enabled = new ArrayList<>();
private Map<String, Map<String, Object>> properties = new HashMap<>();
}

@Service
public class ConfigurableCacheService {

private final CacheDecoratorFactory decoratorFactory;
private final CacheDecoratorConfig config;
private volatile CacheService cacheService;

public ConfigurableCacheService(CacheDecoratorFactory decoratorFactory,
CacheDecoratorConfig config) {
this.decoratorFactory = decoratorFactory;
this.config = config;
this.cacheService = createCacheService();
}

private CacheService createCacheService() {
List<String> decoratorNames = config.getEnabled();
return decoratorFactory.createCacheService(decoratorNames.toArray(new String[0]));
}

// 支持运行时重新配置
@EventListener
public void onConfigChange(ConfigChangeEvent event) {
if (event.getKey().startsWith("cache.decorators")) {
this.cacheService = createCacheService();
log.info("缓存服务装饰器重新配置: {}", config.getEnabled());
}
}

public Object get(String key) {
return cacheService.get(key);
}

public void put(String key, Object value, long expireTime) {
cacheService.put(key, value, expireTime);
}

public void delete(String key) {
cacheService.delete(key);
}
}

第三步:高级装饰器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 加密装饰器
@Component
public class EncryptionDecorator extends CacheDecorator {

private final EncryptionService encryptionService;

public EncryptionDecorator(CacheService cacheService, EncryptionService encryptionService) {
super(cacheService);
this.encryptionService = encryptionService;
}

@Override
public Object get(String key) {
Object encryptedValue = super.get(key);
if (encryptedValue instanceof String) {
try {
return encryptionService.decrypt((String) encryptedValue);
} catch (Exception e) {
log.error("解密失败: key={}", key, e);
return null;
}
}
return encryptedValue;
}

@Override
public void put(String key, Object value, long expireTime) {
try {
String encryptedValue = encryptionService.encrypt(JSON.toJSONString(value));
super.put(key, encryptedValue, expireTime);
} catch (Exception e) {
log.error("加密失败: key={}", key, e);
// 降级处理:存储原始数据
super.put(key, value, expireTime);
}
}

@Override
public String getComponentName() {
return "Encryption-" + super.getComponentName();
}
}

// 限流装饰器
@Component
public class RateLimitDecorator extends CacheDecorator {

private final RateLimiter rateLimiter;
private final int maxRequestsPerSecond;

public RateLimitDecorator(CacheService cacheService, RateLimiter rateLimiter) {
super(cacheService);
this.rateLimiter = rateLimiter;
this.maxRequestsPerSecond = 1000; // 默认限制
}

@Override
public Object get(String key) {
if (!rateLimiter.tryAcquire()) {
log.warn("缓存访问被限流: key={}", key);
throw new RateLimitException("缓存访问频率超限");
}
return super.get(key);
}

@Override
public void put(String key, Object value, long expireTime) {
if (!rateLimiter.tryAcquire()) {
log.warn("缓存写入被限流: key={}", key);
throw new RateLimitException("缓存写入频率超限");
}
super.put(key, value, expireTime);
}

@Override
public String getComponentName() {
return "RateLimit-" + super.getComponentName();
}
}

# 3.3 效果验证

装饰器组合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RestController
@RequestMapping("/cache")
public class CacheController {

@Autowired
private ConfigurableCacheService cacheService;

@GetMapping("/get/{key}")
public ResponseEntity<Object> get(@PathVariable String key) {
Object value = cacheService.get(key);
return ResponseEntity.ok(value);
}

@PostMapping("/put")
public ResponseEntity<String> put(@RequestParam String key,
@RequestBody Object value,
@RequestParam(defaultValue = "3600") long expireTime) {
cacheService.put(key, value, expireTime);
return ResponseEntity.ok("success");
}
}

配置文件示例

1
2
3
4
5
6
7
8
9
10
11
12
13
cache:
decorators:
enabled:
- statistics
- compression
- encryption
properties:
compression:
algorithm: gzip
threshold: 1024
encryption:
algorithm: AES
key-size: 256

性能对比数据

功能组合响应时间内存占用QPS开发复杂度
基础缓存2ms100MB50000
基础 + 统计3ms120MB45000
基础 + 统计 + 压缩8ms80MB35000
基础 + 统计 + 压缩 + 加密15ms90MB25000
继承方式实现15ms110MB25000极高

实践案例:在订单系统的缓存改造中,我们使用装饰器模式实现了灵活的功能组合:

  1. 开发阶段:只启用基础缓存功能
  2. 测试阶段:添加统计装饰器,监控缓存性能
  3. 生产环境:启用压缩装饰器,节省内存成本
  4. 安全要求:添加加密装饰器,保护敏感数据

整个过程无需修改核心缓存代码,只需要调整配置即可。

# 四、避坑指南:实战中的踩坑与解决方案

# 4.1 坑点一:装饰器顺序敏感

问题描述:装饰器的执行顺序会影响最终结果,但代码中没有明确控制顺序。

1
2
3
4
// 错误示例:顺序不确定
CacheService cache = decoratorFactory.createCacheService("compression", "encryption");

// 可能的问题:先压缩后加密 vs 先加密后压缩,结果完全不同

根因分析:装饰器是链式调用,顺序决定了功能的执行顺序。

解决方案:明确定义装饰器顺序规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Component
public class OrderedCacheDecoratorFactory {

// 定义装饰器执行顺序
private static final Map<String, Integer> DECORATOR_ORDER = Map.of(
"ratelimit", 1, // 最外层:限流
"statistics", 2, // 统计
"encryption", 3, // 加密
"compression", 4 // 最内层:压缩
);

public CacheService createCacheService(List<String> decoratorNames) {
// 按预定义顺序排序
List<String> sortedDecorators = decoratorNames.stream()
.filter(DECORATOR_ORDER::containsKey)
.sorted(Comparator.comparing(DECORATOR_ORDER::get))
.collect(Collectors.toList());

CacheService cacheService = getBaseCacheService();

for (String decoratorName : sortedDecorators) {
cacheService = createDecorator(cacheService, decoratorName);
}

return cacheService;
}

// 验证装饰器顺序的合理性
public void validateDecoratorOrder(List<String> decoratorNames) {
List<Integer> orders = decoratorNames.stream()
.filter(DECORATOR_ORDER::containsKey)
.map(DECORATOR_ORDER::get)
.sorted()
.collect(Collectors.toList());

// 检查是否有不合理的组合
if (orders.contains(3) && orders.contains(4) && orders.indexOf(3) > orders.indexOf(4)) {
throw new IllegalArgumentException("加密装饰器必须在压缩装饰器之前");
}
}
}

# 4.2 坑点二:装饰器链过长导致性能问题

问题描述:装饰器链过长时,调用栈深度增加,影响性能和调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 性能问题:装饰器链过长
CacheService cache = new RateLimitDecorator(
new StatisticsDecorator(
new EncryptionDecorator(
new CompressionDecorator(
new ValidationDecorator(
new LoggingDecorator(
new RedisCacheService()
)
)
)
)
)
);

根因分析:每个装饰器都会增加一层方法调用,过多的装饰器会导致调用栈过深。

解决方案:装饰器合并优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
@Component
public class CombinedCacheDecorator implements CacheService {

private final CacheService baseService;
private final List<CacheEnhancer> enhancers;

public CombinedCacheDecorator(CacheService baseService, List<CacheEnhancer> enhancers) {
this.baseService = baseService;
this.enhancers = enhancers;
}

@Override
public Object get(String key) {
// 前置处理
for (CacheEnhancer enhancer : enhancers) {
Object result = enhancer.beforeGet(key);
if (result != null) {
return result;
}
}

// 执行核心逻辑
Object result = baseService.get(key);

// 后置处理
for (CacheEnhancer enhancer : enhancers) {
result = enhancer.afterGet(key, result);
}

return result;
}

@Override
public void put(String key, Object value, long expireTime) {
// 前置处理
for (CacheEnhancer enhancer : enhancers) {
if (!enhancer.beforePut(key, value, expireTime)) {
return; // 被某个增强器拦截
}
}

// 执行核心逻辑
baseService.put(key, value, expireTime);

// 后置处理
for (CacheEnhancer enhancer : enhancers) {
enhancer.afterPut(key, value, expireTime);
}
}
}

// 增强器接口
public interface CacheEnhancer {
Object beforeGet(String key);
Object afterGet(String key, Object result);
boolean beforePut(String key, Object value, long expireTime);
void afterPut(String key, Object value, long expireTime);
}

# 4.3 坑点三:装饰器中的异常传播

问题描述:装饰器中的异常处理不当,导致整个装饰器链失效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 错误示例:异常处理不当
public class StatisticsDecorator extends CacheDecorator {

@Override
public Object get(String key) {
try {
Object result = super.get(key);
// 统计逻辑
recordStatistics(key, result != null);
return result;
} catch (Exception e) {
// 吞掉异常,返回null
log.error("统计装饰器异常", e);
return null; // 错误:掩盖了真正的异常
}
}
}

根因分析:装饰器不应该吞噬异常,应该让异常正常传播或进行适当的包装。

解决方案:统一的异常处理策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public abstract class SafeCacheDecorator implements CacheService {

protected final CacheService cacheService;
protected final String decoratorName;

public SafeCacheDecorator(CacheService cacheService, String decoratorName) {
this.cacheService = cacheService;
this.decoratorName = decoratorName;
}

@Override
public Object get(String key) {
try {
return doGet(key);
} catch (Exception e) {
log.error("{}装饰器执行失败: key={}", decoratorName, key, e);
// 降级处理:直接调用被装饰对象
return cacheService.get(key);
}
}

protected abstract Object doGet(String key) throws Exception;

@Override
public void put(String key, Object value, long expireTime) {
try {
doPut(key, value, expireTime);
} catch (Exception e) {
log.error("{}装饰器执行失败: key={}", decoratorName, key, e);
// 降级处理:直接调用被装饰对象
cacheService.put(key, value, expireTime);
}
}

protected abstract void doPut(String key, Object value, long expireTime) throws Exception;
}

# 五、高级应用:装饰器模式的扩展

# 5.1 动态装饰器

支持运行时动态添加和移除装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Component
public class DynamicCacheService implements CacheService {

private volatile CacheService currentService;
private final List<CacheDecorator> activeDecorators = new CopyOnWriteArrayList<>();

public DynamicCacheService(CacheService baseService) {
this.currentService = baseService;
}

public void addDecorator(CacheDecorator decorator) {
activeDecorators.add(decorator);
rebuildServiceChain();
}

public void removeDecorator(Class<? extends CacheDecorator> decoratorClass) {
activeDecorators.removeIf(decorator -> decoratorClass.isInstance(decorator));
rebuildServiceChain();
}

private void rebuildServiceChain() {
CacheService service = getBaseService();

// 按装饰器的优先级排序
List<CacheDecorator> sortedDecorators = activeDecorators.stream()
.sorted(Comparator.comparing(this::getDecoratorPriority))
.collect(Collectors.toList());

// 重建装饰器链
for (CacheDecorator decorator : sortedDecorators) {
service = decorator.wrap(service);
}

this.currentService = service;
}

@Override
public Object get(String key) {
return currentService.get(key);
}

@Override
public void put(String key, Object value, long expireTime) {
currentService.put(key, value, expireTime);
}
}

# 5.2 装饰器与 AOP 的结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Aspect
@Component
public class CacheDecoratorAspect {

@Autowired
private List<CacheEnhancer> enhancers;

@Around("@annotation(cacheable)")
public Object aroundCacheable(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable {
String key = generateKey(joinPoint, cacheable);

// 前置增强
for (CacheEnhancer enhancer : enhancers) {
Object result = enhancer.beforeGet(key);
if (result != null) {
return result;
}
}

// 执行原方法
Object result = joinPoint.proceed();

// 后置增强
for (CacheEnhancer enhancer : enhancers) {
result = enhancer.afterGet(key, result);
}

return result;
}
}

# 六、总结与延伸

# 6.1 核心观点提炼

装饰器模式的核心价值在于功能的动态组合和透明扩展,它通过以下方式解决了复杂系统的功能扩展问题:

  1. 避免继承爆炸:通过组合而非继承实现功能扩展
  2. 保持接口一致性:装饰器与被装饰对象实现相同接口
  3. 支持动态组合:运行时可以灵活组合不同功能
  4. 符合单一职责:每个装饰器只负责一个特定功能

# 6.2 技术演进趋势

装饰器模式在现代 Java 生态中的演进:

  1. 注解驱动装饰器:使用注解简化装饰器的应用
  2. 函数式装饰器:利用 Lambda 表达式和高阶函数
  3. 响应式装饰器:在 Reactor 和 RxJS 中的应用
  4. 云原生装饰器:在 Service Mesh 和 Sidecar 模式中的体现

# 6.3 应用边界

装饰器模式不是万能的,在以下场景中需要谨慎使用:

  • 性能敏感场景:装饰器链的调用开销可能影响性能
  • 强依赖关系:功能之间有复杂的依赖关系时
  • 接口频繁变更:组件接口变化会影响所有装饰器

# 6.4 后续优化方向

  1. 性能优化:装饰器合并、调用链优化
  2. 监控完善:装饰器执行时间、成功率统计
  3. 配置管理:装饰器的动态配置和热更新
  4. 错误恢复:装饰器失败时的降级和熔断机制

装饰器模式作为结构型设计模式的代表,在功能扩展和组合方面展现出强大的灵活性。通过合理的设计和实践,它能够显著提升系统的可扩展性和可维护性,是构建复杂中间件系统的重要工具。