设计模式系列(12):结构型模式 - 装饰器模式

系列导读:在学习了对象组合后,我们来看如何动态地为对象添加功能。装饰器模式提供了比继承更灵活的功能扩展方式。本系列同步更新在微信公众号: 码农秋, 欢迎关注。

解决什么问题:在不改变原有对象结构的前提下,动态地给对象添加新的功能。提供了用组合替代继承的灵活方案。

在开发中,我们经常需要为对象添加额外的功能,比如给文件读取器添加缓存功能、压缩功能、加密功能等。如果用继承,你需要创建各种组合类:CachedFileReader、CompressedFileReader、EncryptedFileReader、CachedCompressedFileReader…类的数量会急剧膨胀。

装饰器模式提供了一个优雅的解决方案:通过包装的方式,让你可以自由组合各种功能。就像给手机贴膜、装保护壳一样,每个装饰器都为原对象增加一层功能,而且可以随意组合。

本文在系列中的位置

  • 前置知识:组合模式
  • 系列角色:结构型模式核心
  • 难度等级:★★★☆☆(灵活性强,应用广泛)
  • 后续学习:外观模式

目录

1. 模式概述

装饰器模式是一种结构型设计模式,它允许你动态地将新功能附加到对象上,同时又不改变其结构。装饰器模式比继承更灵活,因为它可以在运行时动态地添加或删除功能。通过将功能封装在独立的装饰器类中,可以灵活组合和扩展对象的行为。

定义

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。装饰器通过持有被装饰对象的引用,实现功能的动态叠加。

目的

  • 动态地扩展对象的功能,提升系统灵活性。
  • 避免使用继承导致的类爆炸,简化系统结构。
  • 保持类的单一职责,便于维护和扩展。

2. 使用场景

装饰器模式适用于以下场景:

  1. 动态扩展

    • 需要动态地给对象添加功能,如I/O流、GUI组件等。
    • 需要动态地撤销功能,支持灵活组合。
    • 需要灵活地组合功能,满足多变业务需求。
  2. 避免继承

    • 需要避免使用继承,减少子类数量。
    • 需要避免类爆炸,保持类的简单性。
    • 需要通过组合而非继承扩展功能。
  3. 透明扩展

    • 需要透明地扩展对象,客户端无需感知装饰过程。
    • 需要保持接口一致性,便于递归装饰。
    • 需要支持递归装饰,实现功能叠加。

真实业务背景举例:

  • Java I/O流体系,通过装饰器模式实现缓冲、加密、压缩等功能的动态叠加。
  • Web开发中的请求/响应过滤器链,动态添加认证、日志、压缩等功能。
  • 企业级应用的日志系统,通过装饰器模式灵活组合日志格式、输出方式和安全控制。
  • Web框架的中间件机制,动态叠加认证、限流、缓存等功能。

3. 优缺点分析

优点

  1. 灵活性:动态添加功能,提升系统扩展性。避免继承的局限性,减少子类数量。支持功能组合,满足多变需求。
  2. 单一职责:每个装饰器只负责一个功能,职责清晰。符合单一职责原则,便于维护。提高代码可维护性和复用性。
  3. 开闭原则:符合开闭原则,易于扩展新功能。易于维护和修改,减少对原有代码的影响。支持功能的灵活组合和扩展。

缺点

  1. 复杂性:增加系统复杂度,装饰器层级过多难以理解。增加理解和调试难度,排查问题较难。需要合理设计装饰器结构。
  2. 性能影响:可能影响性能,装饰器链过长时调用开销大。需要额外的对象创建,增加内存消耗。可能影响执行效率,需优化实现。
  3. 设计难度:需要合理设计接口,避免接口膨胀。需要处理装饰器顺序,保证功能正确叠加。需要处理异常情况,保证系统健壮性。

4. 实际应用案例

  1. I/O流处理:文件流装饰(如FileInputStream、BufferedInputStream、DataInputStream等)、缓冲流装饰(提升I/O性能)、压缩流装饰(支持数据压缩和解压)。
  2. GUI组件:滚动条装饰(为文本框、面板等添加滚动条功能)、边框装饰(为组件添加边框、阴影等视觉效果)、事件装饰(为组件动态添加事件处理功能)。
  3. 日志系统:时间戳装饰(为日志添加时间戳)、日志级别装饰(支持不同级别的日志输出)、格式化装饰(支持日志内容格式化)。
  4. 权限控制:认证装饰(为请求添加认证功能)、授权装饰(为操作添加权限校验)、审计装饰(记录操作日志,便于追踪)。

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 设计原则

  1. 保持装饰器的单一职责 :每个装饰器只负责一个功能
  2. 合理设计装饰器顺序 :考虑功能的逻辑依赖关系
  3. 提供装饰器的组合工厂 :简化复杂装饰器链的创建

9.2 实现技巧

  1. 使用构建者模式管理装饰器

    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;
        }
    }
    
  2. 支持装饰器的动态移除 :在某些场景下支持功能的动态禁用

9.3 性能优化

  1. 缓存装饰器实例 :避免重复创建相同的装饰器
  2. 异步装饰器 :对于耗时操作,支持异步处理
  3. 监控装饰器性能 :记录每个装饰器的执行时间

10. 参考资料与延伸阅读

  • 《设计模式:可复用面向对象软件的基础》GoF
  • Effective Java(中文版)
  • https://refactoringguru.cn/design-patterns/decorator
  • https://www.baeldung.com/java-decorator-pattern

本文为设计模式系列第12篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。微信公众号: 码农秋,欢迎关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值