系列导读:在学习了对象组合后,我们来看如何动态地为对象添加功能。装饰器模式提供了比继承更灵活的功能扩展方式。本系列同步更新在微信公众号: 码农秋, 欢迎关注。
解决什么问题:在不改变原有对象结构的前提下,动态地给对象添加新的功能。提供了用组合替代继承的灵活方案。
在开发中,我们经常需要为对象添加额外的功能,比如给文件读取器添加缓存功能、压缩功能、加密功能等。如果用继承,你需要创建各种组合类:CachedFileReader、CompressedFileReader、EncryptedFileReader、CachedCompressedFileReader…类的数量会急剧膨胀。
装饰器模式提供了一个优雅的解决方案:通过包装的方式,让你可以自由组合各种功能。就像给手机贴膜、装保护壳一样,每个装饰器都为原对象增加一层功能,而且可以随意组合。
本文在系列中的位置:
目录
1. 模式概述
装饰器模式是一种结构型设计模式,它允许你动态地将新功能附加到对象上,同时又不改变其结构。装饰器模式比继承更灵活,因为它可以在运行时动态地添加或删除功能。通过将功能封装在独立的装饰器类中,可以灵活组合和扩展对象的行为。
定义
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。装饰器通过持有被装饰对象的引用,实现功能的动态叠加。
目的
- 动态地扩展对象的功能,提升系统灵活性。
- 避免使用继承导致的类爆炸,简化系统结构。
- 保持类的单一职责,便于维护和扩展。
2. 使用场景
装饰器模式适用于以下场景:
-
动态扩展
- 需要动态地给对象添加功能,如I/O流、GUI组件等。
- 需要动态地撤销功能,支持灵活组合。
- 需要灵活地组合功能,满足多变业务需求。
-
避免继承
- 需要避免使用继承,减少子类数量。
- 需要避免类爆炸,保持类的简单性。
- 需要通过组合而非继承扩展功能。
-
透明扩展
- 需要透明地扩展对象,客户端无需感知装饰过程。
- 需要保持接口一致性,便于递归装饰。
- 需要支持递归装饰,实现功能叠加。
真实业务背景举例:
- Java I/O流体系,通过装饰器模式实现缓冲、加密、压缩等功能的动态叠加。
- Web开发中的请求/响应过滤器链,动态添加认证、日志、压缩等功能。
- 企业级应用的日志系统,通过装饰器模式灵活组合日志格式、输出方式和安全控制。
- Web框架的中间件机制,动态叠加认证、限流、缓存等功能。
3. 优缺点分析
优点
- 灵活性:动态添加功能,提升系统扩展性。避免继承的局限性,减少子类数量。支持功能组合,满足多变需求。
- 单一职责:每个装饰器只负责一个功能,职责清晰。符合单一职责原则,便于维护。提高代码可维护性和复用性。
- 开闭原则:符合开闭原则,易于扩展新功能。易于维护和修改,减少对原有代码的影响。支持功能的灵活组合和扩展。
缺点
- 复杂性:增加系统复杂度,装饰器层级过多难以理解。增加理解和调试难度,排查问题较难。需要合理设计装饰器结构。
- 性能影响:可能影响性能,装饰器链过长时调用开销大。需要额外的对象创建,增加内存消耗。可能影响执行效率,需优化实现。
- 设计难度:需要合理设计接口,避免接口膨胀。需要处理装饰器顺序,保证功能正确叠加。需要处理异常情况,保证系统健壮性。
4. 实际应用案例
- I/O流处理:文件流装饰(如FileInputStream、BufferedInputStream、DataInputStream等)、缓冲流装饰(提升I/O性能)、压缩流装饰(支持数据压缩和解压)。
- GUI组件:滚动条装饰(为文本框、面板等添加滚动条功能)、边框装饰(为组件添加边框、阴影等视觉效果)、事件装饰(为组件动态添加事件处理功能)。
- 日志系统:时间戳装饰(为日志添加时间戳)、日志级别装饰(支持不同级别的日志输出)、格式化装饰(支持日志内容格式化)。
- 权限控制:认证装饰(为请求添加认证功能)、授权装饰(为操作添加权限校验)、审计装饰(记录操作日志,便于追踪)。
5. 结构与UML类图
@startuml
package "Decorator Pattern" #DDDDDD {
interface Component {
+ operation(): void
}
class ConcreteComponent implements Component
abstract class Decorator implements Component {
# component: Component
+ operation(): void
}
class ConcreteDecoratorA extends Decorator
class ConcreteDecoratorB extends Decorator
Component <|.. ConcreteComponent
Component <|.. Decorator
Decorator <|-- ConcreteDecoratorA
Decorator <|-- ConcreteDecoratorB
Decorator o-- Component : component
note right: 支持多层装饰器链
}
@enduml
6. 代码示例
6.1 基本结构示例
业务背景: 实现一个可动态扩展功能的组件体系,支持在运行时灵活叠加新功能。
package com.example.patterns.decorator;
import java.util.Objects;
// 组件接口,定义核心操作
public interface Component {
/**
* 执行业务操作
*/
void operation();
/**
* 获取组件描述
*/
String getDescription();
}
// 具体组件,实现Component接口,核心功能实现
public class ConcreteComponent implements Component {
private final String name;
public ConcreteComponent(String name) {
this.name = Objects.requireNonNull(name, "组件名称不能为空");
}
@Override
public void operation() {
try {
// 核心业务逻辑
System.out.println("执行基础组件 [" + name + "] 的核心操作");
} catch (Exception e) {
System.err.println("基础组件操作失败: " + e.getMessage());
throw new RuntimeException("基础组件操作失败", e);
}
}
@Override
public String getDescription() {
return "基础组件: " + name;
}
}
// 装饰器基类,实现Component接口,持有被装饰对象引用
public abstract class Decorator implements Component {
protected final Component component;
/**
* 构造方法注入被装饰对象,便于动态组合
*/
public Decorator(Component component) {
this.component = Objects.requireNonNull(component, "被装饰组件不能为空");
}
@Override
public void operation() {
// 委托给被装饰对象
component.operation();
}
@Override
public String getDescription() {
return component.getDescription();
}
}
// 具体装饰器A,扩展新功能
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
// 新增功能A
addedBehaviorA();
}
@Override
public String getDescription() {
return super.getDescription() + " + 装饰器A";
}
private void addedBehaviorA() {
System.out.println("装饰器A增强:添加功能A的处理逻辑");
}
}
// 具体装饰器B,扩展新功能
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
// 新增功能B
addedBehaviorB();
}
@Override
public String getDescription() {
return super.getDescription() + " + 装饰器B";
}
private void addedBehaviorB() {
System.out.println("装饰器B增强:添加功能B的处理逻辑");
}
}
6.2 企业级应用场景:HTTP请求处理系统
业务背景: 实现一个企业级HTTP请求处理系统,支持动态叠加认证、日志、缓存、限流等功能。
package com.example.patterns.decorator.http;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
// HTTP请求处理接口
public interface HttpRequestHandler {
/**
* 处理HTTP请求
*/
HttpResponse handle(HttpRequest request);
/**
* 获取处理器描述
*/
String getHandlerInfo();
}
// HTTP请求对象
public class HttpRequest {
private final String method;
private final String url;
private final Map<String, String> headers;
private final String body;
private final String clientIp;
public HttpRequest(String method, String url, Map<String, String> headers, String body, String clientIp) {
this.method = method;
this.url = url;
this.headers = headers != null ? new HashMap<>(headers) : new HashMap<>();
this.body = body;
this.clientIp = clientIp;
}
// Getter方法
public String getMethod() { return method; }
public String getUrl() { return url; }
public Map<String, String> getHeaders() { return new HashMap<>(headers); }
public String getBody() { return body; }
public String getClientIp() { return clientIp; }
public String getHeader(String name) {
return headers.get(name);
}
}
// HTTP响应对象
public class HttpResponse {
private int statusCode;
private final Map<String, String> headers;
private String body;
private LocalDateTime timestamp;
public HttpResponse(int statusCode, String body) {
this.statusCode = statusCode;
this.body = body;
this.headers = new HashMap<>();
this.timestamp = LocalDateTime.now();
}
// Getter和Setter方法
public int getStatusCode() { return statusCode; }
public void setStatusCode(int statusCode) { this.statusCode = statusCode; }
public String getBody() { return body; }
public void setBody(String body) { this.body = body; }
public Map<String, String> getHeaders() { return new HashMap<>(headers); }
public LocalDateTime getTimestamp() { return timestamp; }
public void addHeader(String name, String value) {
headers.put(name, value);
}
}
// 基础HTTP处理器
public class BasicHttpHandler implements HttpRequestHandler {
@Override
public HttpResponse handle(HttpRequest request) {
try {
// 基础处理逻辑
System.out.println("BasicHttpHandler: 处理请求 " + request.getMethod() + " " + request.getUrl());
// 模拟业务处理
String responseBody = "Hello from " + request.getUrl();
return new HttpResponse(200, responseBody);
} catch (Exception e) {
System.err.println("基础处理器异常: " + e.getMessage());
return new HttpResponse(500, "Internal Server Error");
}
}
@Override
public String getHandlerInfo() {
return "基础HTTP处理器";
}
}
// HTTP装饰器基类
public abstract class HttpHandlerDecorator implements HttpRequestHandler {
protected final HttpRequestHandler handler;
public HttpHandlerDecorator(HttpRequestHandler handler) {
this.handler = Objects.requireNonNull(handler, "HTTP处理器不能为空");
}
@Override
public HttpResponse handle(HttpRequest request) {
return handler.handle(request);
}
@Override
public String getHandlerInfo() {
return handler.getHandlerInfo();
}
}
// 认证装饰器
public class AuthenticationDecorator extends HttpHandlerDecorator {
private final Map<String, String> validTokens = new ConcurrentHashMap<>();
public AuthenticationDecorator(HttpRequestHandler handler) {
super(handler);
// 初始化一些有效token
validTokens.put("token123", "user1");
validTokens.put("token456", "user2");
}
@Override
public HttpResponse handle(HttpRequest request) {
String token = request.getHeader("Authorization");
if (token == null || !isValidToken(token)) {
System.out.println("AuthenticationDecorator: 认证失败,token无效");
return new HttpResponse(401, "Unauthorized");
}
String user = validTokens.get(token);
System.out.println("AuthenticationDecorator: 用户 " + user + " 认证成功");
return super.handle(request);
}
@Override
public String getHandlerInfo() {
return super.getHandlerInfo() + " + 认证装饰器";
}
private boolean isValidToken(String token) {
return validTokens.containsKey(token);
}
}
// 日志装饰器
public class LoggingDecorator extends HttpHandlerDecorator {
public LoggingDecorator(HttpRequestHandler handler) {
super(handler);
}
@Override
public HttpResponse handle(HttpRequest request) {
long startTime = System.currentTimeMillis();
System.out.println("LoggingDecorator: [" + LocalDateTime.now() + "] 请求开始 - " +
request.getMethod() + " " + request.getUrl() + " from " + request.getClientIp());
try {
HttpResponse response = super.handle(request);
long duration = System.currentTimeMillis() - startTime;
System.out.println("LoggingDecorator: [" + LocalDateTime.now() + "] 请求完成 - " +
"状态码: " + response.getStatusCode() + ", 耗时: " + duration + "ms");
return response;
} catch (Exception e) {
long duration = System.currentTimeMillis() - startTime;
System.err.println("LoggingDecorator: [" + LocalDateTime.now() + "] 请求异常 - " +
"错误: " + e.getMessage() + ", 耗时: " + duration + "ms");
throw e;
}
}
@Override
public String getHandlerInfo() {
return super.getHandlerInfo() + " + 日志装饰器";
}
}
// 缓存装饰器
public class CachingDecorator extends HttpHandlerDecorator {
private final Map<String, HttpResponse> cache = new ConcurrentHashMap<>();
private final long cacheExpirationMs;
public CachingDecorator(HttpRequestHandler handler, long cacheExpirationMs) {
super(handler);
this.cacheExpirationMs = cacheExpirationMs;
}
@Override
public HttpResponse handle(HttpRequest request) {
// 只缓存GET请求
if (!"GET".equals(request.getMethod())) {
return super.handle(request);
}
String cacheKey = generateCacheKey(request);
HttpResponse cachedResponse = cache.get(cacheKey);
if (cachedResponse != null && !isCacheExpired(cachedResponse)) {
System.out.println("CachingDecorator: 缓存命中 - " + request.getUrl());
return cachedResponse;
}
System.out.println("CachingDecorator: 缓存未命中,执行实际处理 - " + request.getUrl());
HttpResponse response = super.handle(request);
// 缓存成功响应
if (response.getStatusCode() == 200) {
cache.put(cacheKey, response);
}
return response;
}
@Override
public String getHandlerInfo() {
return super.getHandlerInfo() + " + 缓存装饰器";
}
private String generateCacheKey(HttpRequest request) {
return request.getMethod() + ":" + request.getUrl();
}
private boolean isCacheExpired(HttpResponse response) {
return System.currentTimeMillis() - response.getTimestamp().toEpochSecond(java.time.ZoneOffset.UTC) * 1000 > cacheExpirationMs;
}
}
// 限流装饰器
public class RateLimitingDecorator extends HttpHandlerDecorator {
private final Map<String, Integer> requestCounts = new ConcurrentHashMap<>();
private final int maxRequestsPerMinute;
public RateLimitingDecorator(HttpRequestHandler handler, int maxRequestsPerMinute) {
super(handler);
this.maxRequestsPerMinute = maxRequestsPerMinute;
}
@Override
public HttpResponse handle(HttpRequest request) {
String clientKey = getClientKey(request);
int currentCount = requestCounts.getOrDefault(clientKey, 0);
if (currentCount >= maxRequestsPerMinute) {
System.out.println("RateLimitingDecorator: 请求被限流 - " + request.getClientIp());
return new HttpResponse(429, "Too Many Requests");
}
requestCounts.put(clientKey, currentCount + 1);
System.out.println("RateLimitingDecorator: 请求通过限流检查 - " + clientKey + " (" + (currentCount + 1) + "/" + maxRequestsPerMinute + ")");
return super.handle(request);
}
@Override
public String getHandlerInfo() {
return super.getHandlerInfo() + " + 限流装饰器";
}
private String getClientKey(HttpRequest request) {
return request.getClientIp() + ":" + (System.currentTimeMillis() / 60000); // 按分钟分组
}
public void resetCounts() {
requestCounts.clear();
}
}
6.3 客户端使用示例
package com.example.patterns.decorator.demo;
import java.util.HashMap;
import java.util.Map;
public class DecoratorDemo {
public static void main(String[] args) {
// 基本装饰器示例
System.out.println("=== 基本装饰器示例 ===");
Component basicComponent = new ConcreteComponent("核心组件");
Component decoratedComponent = new ConcreteDecoratorA(
new ConcreteDecoratorB(basicComponent));
System.out.println("组件描述: " + decoratedComponent.getDescription());
decoratedComponent.operation();
// HTTP处理器装饰器示例
System.out.println("\n=== HTTP处理器装饰器示例 ===");
// 创建基础处理器
HttpRequestHandler basicHandler = new BasicHttpHandler();
// 装饰处理器:日志 -> 认证 -> 缓存 -> 限流 -> 基础处理
HttpRequestHandler decoratedHandler = new LoggingDecorator(
new AuthenticationDecorator(
new CachingDecorator(
new RateLimitingDecorator(basicHandler, 10),
60000))); // 1分钟缓存
System.out.println("处理器信息: " + decoratedHandler.getHandlerInfo());
// 创建测试请求
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "token123");
HttpRequest request1 = new HttpRequest("GET", "/api/users", headers, null, "192.168.1.100");
// 处理请求
System.out.println("\n--- 第一次请求 ---");
HttpResponse response1 = decoratedHandler.handle(request1);
System.out.println("响应状态: " + response1.getStatusCode());
System.out.println("响应内容: " + response1.getBody());
// 第二次相同请求,应该命中缓存
System.out.println("\n--- 第二次请求(应该命中缓存)---");
HttpResponse response2 = decoratedHandler.handle(request1);
System.out.println("响应状态: " + response2.getStatusCode());
// 无认证请求
System.out.println("\n--- 无认证请求 ---");
HttpRequest unauthorizedRequest = new HttpRequest("GET", "/api/users", new HashMap<>(), null, "192.168.1.101");
HttpResponse response3 = decoratedHandler.handle(unauthorizedRequest);
System.out.println("响应状态: " + response3.getStatusCode());
System.out.println("响应内容: " + response3.getBody());
}
// 总结:通过装饰器模式,可以灵活组合各种功能,动态扩展系统能力而不修改原有代码。
}
7. 测试用例
业务背景: 验证装饰器模式的核心功能,包括基本装饰、HTTP处理器装饰和功能叠加。
package com.example.patterns.decorator.test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.*;
import java.util.HashMap;
import java.util.Map;
public class DecoratorPatternTest {
private Component basicComponent;
private HttpRequestHandler basicHandler;
@BeforeEach
public void setUp() {
basicComponent = new ConcreteComponent("测试组件");
basicHandler = new BasicHttpHandler();
}
@Test
public void testBasicDecorator() {
// 测试基本装饰器功能
Component decoratedA = new ConcreteDecoratorA(basicComponent);
Component decoratedB = new ConcreteDecoratorB(basicComponent);
assertTrue("装饰器A描述应包含原组件", decoratedA.getDescription().contains("测试组件"));
assertTrue("装饰器A描述应包含装饰器A", decoratedA.getDescription().contains("装饰器A"));
assertTrue("装饰器B描述应包含原组件", decoratedB.getDescription().contains("测试组件"));
assertTrue("装饰器B描述应包含装饰器B", decoratedB.getDescription().contains("装饰器B"));
// 测试操作不抛异常
assertDoesNotThrow(() -> {
decoratedA.operation();
decoratedB.operation();
});
}
@Test
public void testChainedDecorators() {
// 测试装饰器链
Component chainedDecorator = new ConcreteDecoratorA(
new ConcreteDecoratorB(basicComponent));
String description = chainedDecorator.getDescription();
assertTrue("应包含原组件描述", description.contains("测试组件"));
assertTrue("应包含装饰器A", description.contains("装饰器A"));
assertTrue("应包含装饰器B", description.contains("装饰器B"));
assertDoesNotThrow(() -> chainedDecorator.operation());
}
@Test
public void testNullComponentValidation() {
// 测试空组件验证
assertThrows(NullPointerException.class, () -> {
new ConcreteDecoratorA(null);
});
assertThrows(NullPointerException.class, () -> {
new ConcreteDecoratorB(null);
});
}
@Test
public void testHttpBasicHandler() {
// 测试基础HTTP处理器
Map<String, String> headers = new HashMap<>();
HttpRequest request = new HttpRequest("GET", "/test", headers, null, "127.0.0.1");
HttpResponse response = basicHandler.handle(request);
assertEquals("状态码应为200", 200, response.getStatusCode());
assertNotNull("响应体不应为空", response.getBody());
assertTrue("响应体应包含URL", response.getBody().contains("/test"));
assertEquals("处理器信息正确", "基础HTTP处理器", basicHandler.getHandlerInfo());
}
@Test
public void testAuthenticationDecorator() {
// 测试认证装饰器
HttpRequestHandler authHandler = new AuthenticationDecorator(basicHandler);
// 有效token测试
Map<String, String> validHeaders = new HashMap<>();
validHeaders.put("Authorization", "token123");
HttpRequest validRequest = new HttpRequest("GET", "/test", validHeaders, null, "127.0.0.1");
HttpResponse validResponse = authHandler.handle(validRequest);
assertEquals("有效token应返回200", 200, validResponse.getStatusCode());
// 无效token测试
Map<String, String> invalidHeaders = new HashMap<>();
invalidHeaders.put("Authorization", "invalid_token");
HttpRequest invalidRequest = new HttpRequest("GET", "/test", invalidHeaders, null, "127.0.0.1");
HttpResponse invalidResponse = authHandler.handle(invalidRequest);
assertEquals("无效token应返回401", 401, invalidResponse.getStatusCode());
// 无token测试
HttpRequest noTokenRequest = new HttpRequest("GET", "/test", new HashMap<>(), null, "127.0.0.1");
HttpResponse noTokenResponse = authHandler.handle(noTokenRequest);
assertEquals("无token应返回401", 401, noTokenResponse.getStatusCode());
}
@Test
public void testLoggingDecorator() {
// 测试日志装饰器
HttpRequestHandler loggingHandler = new LoggingDecorator(basicHandler);
Map<String, String> headers = new HashMap<>();
HttpRequest request = new HttpRequest("GET", "/test", headers, null, "127.0.0.1");
HttpResponse response = loggingHandler.handle(request);
assertEquals("应返回正确状态码", 200, response.getStatusCode());
assertTrue("处理器信息应包含日志装饰器", loggingHandler.getHandlerInfo().contains("日志装饰器"));
}
@Test
public void testCachingDecorator() {
// 测试缓存装饰器
HttpRequestHandler cachingHandler = new CachingDecorator(basicHandler, 60000); // 1分钟缓存
Map<String, String> headers = new HashMap<>();
HttpRequest getRequest = new HttpRequest("GET", "/test", headers, null, "127.0.0.1");
// 第一次请求
HttpResponse response1 = cachingHandler.handle(getRequest);
assertEquals("第一次请求应成功", 200, response1.getStatusCode());
// 第二次相同请求,应该命中缓存
HttpResponse response2 = cachingHandler.handle(getRequest);
assertEquals("第二次请求应成功", 200, response2.getStatusCode());
// POST请求不应被缓存
HttpRequest postRequest = new HttpRequest("POST", "/test", headers, "body", "127.0.0.1");
HttpResponse postResponse = cachingHandler.handle(postRequest);
assertEquals("POST请求应成功", 200, postResponse.getStatusCode());
}
@Test
public void testRateLimitingDecorator() {
// 测试限流装饰器
HttpRequestHandler rateLimitHandler = new RateLimitingDecorator(basicHandler, 2); // 每分钟最多2个请求
Map<String, String> headers = new HashMap<>();
HttpRequest request = new HttpRequest("GET", "/test", headers, null, "127.0.0.1");
// 前两个请求应该成功
HttpResponse response1 = rateLimitHandler.handle(request);
assertEquals("第一个请求应成功", 200, response1.getStatusCode());
HttpResponse response2 = rateLimitHandler.handle(request);
assertEquals("第二个请求应成功", 200, response2.getStatusCode());
// 第三个请求应该被限流
HttpResponse response3 = rateLimitHandler.handle(request);
assertEquals("第三个请求应被限流", 429, response3.getStatusCode());
// 重置计数器
((RateLimitingDecorator) rateLimitHandler).resetCounts();
HttpResponse response4 = rateLimitHandler.handle(request);
assertEquals("重置后的请求应成功", 200, response4.getStatusCode());
}
@Test
public void testComplexDecoratorChain() {
// 测试复杂装饰器链
HttpRequestHandler complexHandler = new LoggingDecorator(
new AuthenticationDecorator(
new CachingDecorator(
new RateLimitingDecorator(basicHandler, 10),
60000)));
String handlerInfo = complexHandler.getHandlerInfo();
assertTrue("应包含所有装饰器", handlerInfo.contains("基础HTTP处理器"));
assertTrue("应包含限流装饰器", handlerInfo.contains("限流装饰器"));
assertTrue("应包含缓存装饰器", handlerInfo.contains("缓存装饰器"));
assertTrue("应包含认证装饰器", handlerInfo.contains("认证装饰器"));
assertTrue("应包含日志装饰器", handlerInfo.contains("日志装饰器"));
// 测试有效请求
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "token123");
HttpRequest request = new HttpRequest("GET", "/test", headers, null, "127.0.0.1");
HttpResponse response = complexHandler.handle(request);
assertEquals("复杂装饰器链应正常工作", 200, response.getStatusCode());
}
@Test
public void testHttpRequestObject() {
// 测试HTTP请求对象
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("Authorization", "Bearer token");
HttpRequest request = new HttpRequest("POST", "/api/test", headers, "test body", "192.168.1.1");
assertEquals("GET", "POST", request.getMethod());
assertEquals("URL正确", "/api/test", request.getUrl());
assertEquals("请求体正确", "test body", request.getBody());
assertEquals("客户端IP正确", "192.168.1.1", request.getClientIp());
assertEquals("Content-Type头正确", "application/json", request.getHeader("Content-Type"));
assertEquals("Authorization头正确", "Bearer token", request.getHeader("Authorization"));
// 测试headers的不可变性
Map<String, String> returnedHeaders = request.getHeaders();
returnedHeaders.put("X-Test", "test");
assertNull("原请求不应受影响", request.getHeader("X-Test"));
}
@Test
public void testHttpResponseObject() {
// 测试HTTP响应对象
HttpResponse response = new HttpResponse(200, "Success");
assertEquals("状态码正确", 200, response.getStatusCode());
assertEquals("响应体正确", "Success", response.getBody());
assertNotNull("时间戳不应为空", response.getTimestamp());
response.addHeader("Content-Type", "application/json");
response.addHeader("Cache-Control", "no-cache");
assertEquals("Content-Type头正确", "application/json", response.getHeaders().get("Content-Type"));
assertEquals("Cache-Control头正确", "no-cache", response.getHeaders().get("Cache-Control"));
response.setStatusCode(404);
response.setBody("Not Found");
assertEquals("状态码已更新", 404, response.getStatusCode());
assertEquals("响应体已更新", "Not Found", response.getBody());
}
}
8. 常见误区与反例
8.1 常见误区
-
误区1 :装饰器链过长
// 错误示例:装饰器链过长,难以理解和维护 Component overDecorated = new DecoratorA(new DecoratorB(new DecoratorC( new DecoratorD(new DecoratorE(new DecoratorF(basicComponent))))));
正确做法:合理控制装饰器层级,必要时使用工厂模式或构建者模式。
-
误区2 :装饰器顺序错误
// 错误示例:认证装饰器在日志装饰器之后 HttpRequestHandler wrongOrder = new AuthenticationDecorator( new LoggingDecorator(basicHandler)); // 这样无法记录认证失败的日志
-
误区3 :忽略性能影响
// 错误示例:每次都创建新的装饰器 public Component getDecoratedComponent() { return new ConcreteDecoratorA(new ConcreteDecoratorB(basicComponent)); }
8.2 反例分析
- 反例1 :装饰器承担过多职责,违反单一职责原则
- 反例2 :装饰器之间存在强耦合,难以独立使用
- 反例3 :忽略异常处理,装饰器链中异常传播不当
9. 最佳实践
9.1 设计原则
- 保持装饰器的单一职责 :每个装饰器只负责一个功能
- 合理设计装饰器顺序 :考虑功能的逻辑依赖关系
- 提供装饰器的组合工厂 :简化复杂装饰器链的创建
9.2 实现技巧
-
使用构建者模式管理装饰器 :
public class HttpHandlerBuilder { public static HttpHandlerBuilder create(HttpRequestHandler handler) { return new HttpHandlerBuilder(handler); } public HttpHandlerBuilder withLogging() { handler = new LoggingDecorator(handler); return this; } public HttpHandlerBuilder withAuthentication() { handler = new AuthenticationDecorator(handler); return this; } public HttpRequestHandler build() { return handler; } }
-
支持装饰器的动态移除 :在某些场景下支持功能的动态禁用
9.3 性能优化
- 缓存装饰器实例 :避免重复创建相同的装饰器
- 异步装饰器 :对于耗时操作,支持异步处理
- 监控装饰器性能 :记录每个装饰器的执行时间
10. 参考资料与延伸阅读
- 《设计模式:可复用面向对象软件的基础》GoF
- Effective Java(中文版)
- https://refactoringguru.cn/design-patterns/decorator
- https://www.baeldung.com/java-decorator-pattern
本文为设计模式系列第12篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。微信公众号: 码农秋,欢迎关注。