设计模式详解-装饰器模式
设计模式详解:装饰器模式
一、模式概述
装饰器模式(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代理、中间件管道、请求过滤器等基础设施无一不是装饰器思想的延伸。理解装饰器模式,意味着掌握了在不修改既有代码的前提下扩展系统能力的核心技艺——这是软件工程中最具实践价值的设计智慧之一。