设计模式详解-装饰器模式

设计模式详解:装饰器模式

一、模式概述

装饰器模式(Decorator Pattern)是结构型设计模式中最具动态扩展能力的模式,其核心意图在于动态地给一个对象添加一些额外的职责,而无需修改其源代码或影响其他对象。与继承相比,装饰器模式提供了更为灵活的替代方案,能够在运行时以透明的方式叠加功能,形成对象能力的"组合爆炸"而非"继承爆炸"。

这一模式的命名源自现实生活中的装饰行为——为一面白墙挂上画作、为一杯咖啡添加奶泡与糖浆。每一种装饰都建立在既有基础之上,既保留了原有的核心功能,又赋予了新的外在表现。关键在于,装饰的过程是动态的、可逆的、可叠加的,而非一次性固化的改造。

装饰器模式的深层价值在于遵循开闭原则的同时实现功能扩展。继承虽然也能扩展功能,却在编译期静态绑定,且子类与父类形成强耦合的层次结构。当功能组合维度增多时,继承体系呈现指数级膨胀:咖啡有浓缩、美式、拿铁;每种可加奶、加糖、加香草;每种奶可选全脂、脱脂、燕麦——继承方案需要OatMilkVanillaLatte这样的类名,而装饰器方案只需new Vanilla(new OatMilk(new Latte()))

二、模式结构

装饰器模式包含四个核心角色,形成递归包装的结构:

组件接口(Component):定义对象的核心功能接口,是被装饰者和装饰器的共同超类型。

具体组件(Concrete Component):实现组件接口,代表需要被装饰的基础对象。

抽象装饰器(Decorator):实现组件接口,并持有一个组件接口的引用,作为所有具体装饰器的基类。

具体装饰器(Concrete Decorator):继承抽象装饰器,在调用被包装对象的方法前后添加额外行为。

这一结构的精妙之处在于递归一致性:装饰器与被装饰者实现同一接口,客户端无法也无须区分二者。装饰器可以装饰具体组件,也可以装饰其他装饰器,形成任意深度的嵌套链条。

三、深度案例:企业级API网关的请求处理管道

以下展示一个真实场景下的装饰器模式应用——云原生API网关的请求/响应处理流水线,支持认证、限流、缓存、日志、加密等可插拔能力的动态组合。

3.1 组件接口:HTTP处理器

java
/** * 组件接口:HTTP请求处理器 * 所有具体处理器和装饰器均实现此接口 */ public interface HttpHandler { // 核心方法:处理请求并返回响应 HttpResponse handle(HttpRequest request); // 元数据:获取处理器名称,用于监控和调试 String getName(); // 元数据:获取处理器的执行优先级 int getOrder(); } // 具体组件:基础业务处理器 @Component public class BusinessHttpHandler implements HttpHandler { @Autowired private RouteRegistry routeRegistry; @Autowired private ServiceInstanceSelector instanceSelector; @Override public HttpResponse handle(HttpRequest request) { // 1. 路由匹配 Route route = routeRegistry.match(request); // 2. 服务实例选择 ServiceInstance instance = instanceSelector.select(route.getServiceId()); // 3. 构建转发请求 HttpRequest forwardRequest = buildForwardRequest(request, route, instance); // 4. 实际调用下游服务 return HttpClient.create() .request(forwardRequest.getMethod()) .uri(instance.buildUri(route.getPath())) .send((req, out) -> out.sendObject(forwardRequest.getBody())) .responseSingle((res, content) -> content.asString() .map(body -> new HttpResponse(res.status().code(), body))) .block(Duration.ofSeconds(30)); } @Override public String getName() { return "business"; } @Override public int getOrder() { return Integer.MAX_VALUE; } // 最后执行 }

3.2 抽象装饰器与基础设施

java
/** * 抽象装饰器:HTTP处理器装饰基类 * 提供模板方法模式的支持,规范装饰器行为 */ public abstract class HttpHandlerDecorator implements HttpHandler { // 被装饰的对象,可以是具体组件或其他装饰器 protected final HttpHandler delegate; // 可选:装饰器配置 protected final DecoratorConfig config; public HttpHandlerDecorator(HttpHandler delegate) { this(delegate, DecoratorConfig.defaults()); } public HttpHandlerDecorator(HttpHandler delegate, DecoratorConfig config) { this.delegate = delegate; this.config = config; } @Override public HttpResponse handle(HttpRequest request) { // 模板方法:前置处理 Optional<HttpResponse> earlyResponse = beforeHandle(request); if (earlyResponse.isPresent()) { return earlyResponse.get(); // 短路返回 } // 调用被装饰对象 HttpResponse response = delegate.handle(request); // 模板方法:后置处理 return afterHandle(request, response); } // 子类可覆盖的前置处理钩子 protected Optional<HttpResponse> beforeHandle(HttpRequest request) { return Optional.empty(); } // 子类可覆盖的后置处理钩子 protected HttpResponse afterHandle(HttpRequest request, HttpResponse response) { return response; } @Override public String getName() { return this.getClass().getSimpleName() + "->" + delegate.getName(); } @Override public int getOrder() { // 装饰器的顺序通常由装配逻辑控制,此处返回中性值 return 0; } // 获取装饰链最内层的组件 public HttpHandler getInnermostHandler() { if (delegate instanceof HttpHandlerDecorator) { return ((HttpHandlerDecorator) delegate).getInnermostHandler(); } return delegate; } }

3.3 具体装饰器:横切关注点实现

java
/** * 认证装饰器:JWT令牌验证 */ @Component public class AuthenticationDecorator extends HttpHandlerDecorator { private final JwtTokenValidator tokenValidator; private final UserDetailsService userDetailsService; private final Set<String> publicPaths; public AuthenticationDecorator(HttpHandler delegate, JwtTokenValidator validator, UserDetailsService userService, Set<String> publicPaths) { super(delegate); this.tokenValidator = validator; this.userDetailsService = userService; this.publicPaths = publicPaths; } @Override protected Optional<HttpResponse> beforeHandle(HttpRequest request) { String path = request.getPath(); // 公开路径跳过认证 if (publicPaths.stream().anyMatch(path::startsWith)) { return Optional.empty(); } String authHeader = request.getHeader("Authorization"); if (authHeader == null || !authHeader.startsWith("Bearer ")) { return Optional.of(HttpResponse.unauthorized("Missing or invalid token")); } String token = authHeader.substring(7); try { Claims claims = tokenValidator.validate(token); UserDetails user = userDetailsService.loadById(claims.getSubject()); // 将用户信息附加到请求上下文,供下游使用 request.setAttribute("user", user); request.setAttribute("claims", claims); return Optional.empty(); } catch (ExpiredJwtException e) { return Optional.of(HttpResponse.unauthorized("Token expired")); } catch (JwtException e) { return Optional.of(HttpResponse.unauthorized("Invalid token")); } } @Override protected HttpResponse afterHandle(HttpRequest request, HttpResponse response) { // 可选:在响应中添加令牌刷新头 UserDetails user = request.getAttribute("user"); if (user != null && shouldRefresh(request.getAttribute("claims"))) { String newToken = tokenValidator.refresh(user); response.addHeader("X-Refresh-Token", newToken); } return response; } } /** * 限流装饰器:令牌桶算法 */ @Component public class RateLimitDecorator extends HttpHandlerDecorator { private final RateLimiter rateLimiter; private final RateLimitStrategy strategy; public RateLimitDecorator(HttpHandler delegate, RateLimiter limiter, RateLimitStrategy strategy) { super(delegate); this.rateLimiter = limiter; this.strategy = strategy; } @Override protected Optional<HttpResponse> beforeHandle(HttpRequest request) { String key = strategy.resolveKey(request); // 按IP、用户、API等维度 RateLimitResult result = rateLimiter.tryAcquire(key, strategy.getPermits(request), strategy.getTimeout(request)); if (!result.isAllowed()) { HttpResponse response = HttpResponse.tooManyRequests(); response.addHeader("X-RateLimit-Limit", String.valueOf(result.getLimit())); response.addHeader("X-RateLimit-Remaining", "0"); response.addHeader("X-RateLimit-Reset", String.valueOf(result.getResetTime())); return Optional.of(response); } // 将限流信息存入请求属性,供后置处理使用 request.setAttribute("rateLimitResult", result); return Optional.empty(); } @Override protected HttpResponse afterHandle(HttpRequest request, HttpResponse response) { RateLimitResult result = request.getAttribute("rateLimitResult"); if (result != null) { response.addHeader("X-RateLimit-Limit", String.valueOf(result.getLimit())); response.addHeader("X-RateLimit-Remaining", String.valueOf(result.getRemaining())); } return response; } } /** * 缓存装饰器:多级缓存策略 */ @Component public class CacheDecorator extends HttpHandlerDecorator { private final CacheManager cacheManager; private final CacheKeyGenerator keyGenerator; private final CacheConfig cacheConfig; public CacheDecorator(HttpHandler delegate, CacheManager cacheManager, CacheKeyGenerator keyGenerator, CacheConfig config) { super(delegate); this.cacheManager = cacheManager; this.keyGenerator = keyGenerator; this.cacheConfig = config; } @Override protected Optional<HttpResponse> beforeHandle(HttpRequest request) { if (!cacheConfig.isCacheable(request)) { return Optional.empty(); } String cacheKey = keyGenerator.generate(request); // L1缓存:本地Caffeine HttpResponse cached = cacheManager.getLocal(cacheKey); if (cached != null) { cached.addHeader("X-Cache", "HIT-LOCAL"); return Optional.of(cached); } // L2缓存:分布式Redis cached = cacheManager.getRemote(cacheKey); if (cached != null) { cacheManager.putLocal(cacheKey, cached); // 回填本地缓存 cached.addHeader("X-Cache", "HIT-REMOTE"); return Optional.of(cached); } // 缓存未命中,标记请求以便后置处理存储 request.setAttribute("cacheKey", cacheKey); request.setAttribute("cacheable", true); return Optional.empty(); } @Override protected HttpResponse afterHandle(HttpRequest request, HttpResponse response) { Boolean cacheable = request.getAttribute("cacheable"); if (Boolean.TRUE.equals(cacheable) && cacheConfig.isSuccessResponse(response)) { String cacheKey = request.getAttribute("cacheKey"); Duration ttl = cacheConfig.computeTtl(request, response); cacheManager.putLocal(cacheKey, response, ttl.dividedBy(2)); cacheManager.putRemote(cacheKey, response, ttl); response.addHeader("X-Cache", "MISS"); response.addHeader("Cache-Control", "max-age=" + ttl.getSeconds()); } return response; } } /** * 日志与监控装饰器:分布式追踪与指标采集 */ @Component public class ObservabilityDecorator extends HttpHandlerDecorator { private final Tracer tracer; private final MeterRegistry meterRegistry; public ObservabilityDecorator(HttpHandler delegate, Tracer tracer, MeterRegistry registry) { super(delegate); this.tracer = tracer; this.meterRegistry = registry; } @Override public HttpResponse handle(HttpRequest request) { Span span = tracer.nextSpan() .name("gateway-request") .tag("path", request.getPath()) .tag("method", request.getMethod()) .start(); Timer.Sample sample = Timer.start(meterRegistry); HttpResponse response = null; Throwable error = null; try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) { // 传播追踪上下文到下游 request.addHeader("X-B3-TraceId", span.context().traceId()); request.addHeader("X-B3-SpanId", span.context().spanId()); response = super.handle(request); return response; } catch (Exception e) { error = e; span.error(e); throw e; } finally { sample.stop(meterRegistry.timer("gateway.request", "path", request.getPath(), "status", response != null ? String.valueOf(response.getStatus()) : "error")); span.tag("status", response != null ? String.valueOf(response.getStatus()) : "error"); if (error != null) { span.tag("error.type", error.getClass().getSimpleName()); } span.end(); } } } /** * 响应加密装饰器:敏感字段脱敏与传输加密 */ @Component public class EncryptionDecorator extends HttpHandlerDecorator { private final FieldEncryptionService encryptionService; private final Set<String> sensitiveFields; public EncryptionDecorator(HttpHandler delegate, FieldEncryptionService service, Set<String> sensitiveFields) { super(delegate); this.encryptionService = service; this.sensitiveFields = sensitiveFields; } @Override protected HttpResponse afterHandle(HttpRequest request, HttpResponse response) { if (!request.hasHeader("X-Encrypt-Response")) { return response; } JsonNode body = response.getBodyAsJson(); encryptSensitiveFields(body, ""); response.setBody(encryptionService.encryptBody(body)); response.addHeader("X-Encryption-Version", "AES-256-GCM-v1"); return response; } private void encryptSensitiveFields(JsonNode node, String path) { if (node.isObject()) { ObjectNode objNode = (ObjectNode) node; objNode.fields().forEachRemaining(entry -> { String fieldPath = path + "." + entry.getKey(); if (sensitiveFields.contains(fieldPath)) { objNode.put(entry.getKey(), encryptionService.encryptField(entry.getValue().asText())); } else { encryptSensitiveFields(entry.getValue(), fieldPath); } }); } else if (node.isArray()) { for (int i = 0; i < node.size(); i++) { encryptSensitiveFields(node.get(i), path + "[" + i + "]"); } } } }

3.4 装饰器装配引擎:动态组合与配置驱动

java
/** * 装饰器装配引擎:基于配置动态构建处理管道 */ @Component public class HandlerPipelineFactory { @Autowired private ApplicationContext context; @Autowired private GatewayProperties properties; /** * 为特定路由构建处理管道 */ public HttpHandler buildPipeline(Route route) { // 从最内层的业务处理器开始 HttpHandler handler = context.getBean(BusinessHttpHandler.class); // 获取路由特定的装饰器配置 List<DecoratorDefinition> decorators = resolveDecorators(route); // 按优先级排序,优先级高的在外层(后执行前置、先执行后置) decorators.sort(Comparator.comparingInt(DecoratorDefinition::getPriority).reversed()); // 逐层包装 for (DecoratorDefinition def : decorators) { handler = instantiateDecorator(def, handler); } return handler; } private HttpHandler instantiateDecorator(DecoratorDefinition def, HttpHandler delegate) { Class<? extends HttpHandlerDecorator> decoratorClass = def.getDecoratorClass(); // 通过反射或Spring的BeanDefinition机制创建装饰器实例 // 支持构造函数注入被装饰对象和配置参数 Constructor<? extends HttpHandlerDecorator> constructor = findSuitableConstructor(decoratorClass); Object[] args = resolveConstructorArgs(constructor, def, delegate); try { return constructor.newInstance(args); } catch (Exception e) { throw new DecoratorInstantiationException(def.getName(), e); } } private List<DecoratorDefinition> resolveDecorators(Route route) { List<DecoratorDefinition> result = new ArrayList<>(); // 全局默认装饰器 result.addAll(properties.getGlobalDecorators()); // 服务级别装饰器 result.addAll(properties.getServiceDecorators(route.getServiceId())); // 路由特定装饰器 result.addAll(route.getDecorators()); // 去重:同类型装饰器,路由级覆盖服务级,服务级覆盖全局 Map<String, DecoratorDefinition> merged = new LinkedHashMap<>(); for (DecoratorDefinition def : result) { merged.merge(def.getType(), def, (existing, incoming) -> incoming); } return new ArrayList<>(merged.values()); } } // 配置示例(YAML) /* routes: - id: payment-api path: /api/payments/** serviceId: payment-service decorators: - type: auth priority: 100 config: requiredScopes: ["payment:write"] - type: rateLimit priority: 200 config: limit: 1000 window: 60s - type: cache priority: 300 config: ttl: 300s cacheableMethods: [GET] - type: encrypt priority: 50 config: sensitiveFields: ["$.cardNumber", "$.cvv"] */

四、装饰器模式的高级形态

4.1 异步反应式装饰器

在WebFlux等反应式编程模型中,装饰器需处理Mono/Flux的延迟执行特性:

java
public class ReactiveCacheDecorator implements ReactiveHttpHandler { private final ReactiveHttpHandler delegate; private final ReactiveCacheManager cacheManager; @Override public Mono<HttpResponse> handle(HttpRequest request) { String cacheKey = generateKey(request); return cacheManager.get(cacheKey) .switchIfEmpty( delegate.handle(request) .flatMap(response -> cacheManager.put(cacheKey, response) .thenReturn(response)) ); } }

4.2 装饰器与责任链的融合

当装饰器需要支持条件短路和动态重排时,可引入责任链模式:

java
public interface HandlerChain { Mono<HttpResponse> proceed(HttpRequest request); } public class ChainedRateLimitDecorator implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return checkRateLimit(exchange) .flatMap(allowed -> { if (!allowed) { return writeRateLimitResponse(exchange); } return chain.filter(exchange); // 传递给链中的下一个 }); } }

Spring Cloud Gateway的GatewayFilter链即为此模式的工业级实现。

五、Java I/O中的经典范式

Java标准库的I/O体系是装饰器模式最教科书式的示范:

java
// 基础组件:FileInputStream InputStream fileStream = new FileInputStream("data.txt"); // 装饰:缓冲能力 InputStream bufferedStream = new BufferedInputStream(fileStream); // 装饰:数据类型解析能力 DataInputStream dataStream = new DataInputStream(bufferedStream); // 装饰:对象序列化能力 ObjectInputStream objectStream = new ObjectInputStream(dataStream); // 每一层装饰都增强功能,同时保持InputStream接口的一致性 MyCustomObject obj = (MyCustomObject) objectStream.readObject();

这一设计的深远影响在于:任何需要InputStream的地方,都可以传入任意装饰后的变体,实现了真正的即插即用。

六、装饰器与相关模式的辨析

装饰器 vs 继承:继承在编译期静态绑定功能,修改需重新编译;装饰器在运行期动态组合,支持热插拔。继承是"is-a"关系,装饰器是"has-a"关系的透明包装。

装饰器 vs 代理:代理模式控制对对象的访问,通常不改变接口语义;装饰器模式增强对象的功能,可能改变行为表现。代理的代表是权限控制、延迟加载;装饰器的代表是缓存、压缩、加密。

装饰器 vs 策略:策略模式改变算法的内部实现,保持接口不变;装饰器模式在接口调用前后添加行为。二者可结合:装饰器使用策略对象实现具体增强逻辑。

七、设计陷阱与规避策略

陷阱一:装饰器顺序依赖

某些装饰器存在隐式的执行顺序要求:认证必须在审计之前,缓存必须在限流之后。解决方案:显式优先级机制、装配时的合法性校验、或文档化约束。

陷阱二:过度装饰导致的性能损耗

每层装饰都引入方法调用开销,深度嵌套可能影响性能。解决方案:在热点路径使用内联优化、或提供"裸调"的快捷路径。

陷阱三:异常处理与资源泄漏

装饰器链条中的异常可能绕过某些清理逻辑。解决方案:统一使用try-finally或try-with-resources,确保每层装饰都有机会释放资源。

八、结语

装饰器模式是面向对象设计中"组合优于继承"原则的最直接体现。它赋予对象以洋葱般的层次结构,每一层都薄而专注,叠加起来却形成强大的能力矩阵。在现代云原生架构中,Sidecar代理、中间件管道、请求过滤器等基础设施无一不是装饰器思想的延伸。理解装饰器模式,意味着掌握了在不修改既有代码的前提下扩展系统能力的核心技艺——这是软件工程中最具实践价值的设计智慧之一。

返回知识中心