装饰器模式(Decorator Pattern)是一种结构型设计模式,允许在不改变对象自身结构的情况下,动态地添加新功能。它通过将对象放入特殊的包装类中(称为“装饰器”)来实现功能的扩展,是继承的一种灵活替代方案。
一、 核心思想
- 动态扩展:在运行时添加/移除功能,而非编译时
- 组合优于继承:通过对象组合实现功能叠加,避免类爆炸
- 透明性:装饰后的对象与原对象接口一致,对客户端透明
二、典型使用场景
- I/O 流操作(Java 原生) 如 InputStream, BufferedInputStream, DataInputStream 等,都是典型的装饰器模式应用
- 权限控制/日志记录等通用功能增强 在不改变核心业务逻辑的前提下,为服务添加日志、缓存、安全等功能。
- UI 组件扩展 比如按钮组件加上边框、阴影、滚动条等效果。
- Spring 中的 AOP(面向切面编程) Spring 使用了类似装饰器的思想来实现方法拦截和增强。
三、代码实现
1. 传统装饰器模式实现
以下是一个典型的装饰器模式实现,模拟为文本消息添加加密、压缩等动态功能。
1.1 定义接口(Component)
// 定义基础功能接口
public interface TextMessage {
String getContent(); // 获取文本内容
}
1.2 实现具体组件(Concrete Component)
// 基础文本消息实现
public class PlainTextMessage implements TextMessage {
private String content;
public PlainTextMessage(String content) {
this.content = content;
}
@Override
public String getContent() {
return content;
}
}
1.3 定义装饰器抽象类(Decorator)
// 所有装饰器的基类,保持接口一致
public abstract class TextMessageDecorator implements TextMessage {
protected TextMessage decoratedText;
public TextMessageDecorator(TextMessage decoratedText) {
this.decoratedText = decoratedText;
}
@Override
public String getContent() {
return decoratedText.getContent();
}
}
1.4 实现具体装饰器(Concrete Decorators)
// 添加加密功能的装饰器
public class EncryptedMessageDecorator extends TextMessageDecorator {
public EncryptedMessageDecorator(TextMessage decoratedText) {
super(decoratedText);
}
@Override
public String getContent() {
String originalContent = super.getContent();
// 简单加密(实际可用 AES 等算法)
return encrypt(originalContent);
}
private String encrypt(String content) {
// 模拟加密:将字符串反转
return new StringBuilder(content).reverse().toString();
}
}
// 添加压缩功能的装饰器
public class CompressedMessageDecorator extends TextMessageDecorator {
public CompressedMessageDecorator(TextMessage decoratedText) {
super(decoratedText);
}
@Override
public String getContent() {
String originalContent = super.getContent();
// 简单压缩(实际可用 GZIP 等)
return compress(originalContent);
}
private String compress(String content) {
// 模拟压缩:移除空格
return content.replaceAll(" ", "");
}
}
1.5 客户端调用
public class Client {
public static void main(String[] args) {
// 原始文本
TextMessage message = new PlainTextMessage("Hello, this is a secret message!");
// 加密装饰
TextMessage encryptedMessage = new EncryptedMessageDecorator(message);
System.out.println("Encrypted: " + encryptedMessage.getContent());
// 输出: "!egassem terces a si siht ,olleH"
// 先加密再压缩
TextMessage encryptedAndCompressedMessage = new CompressedMessageDecorator(
new EncryptedMessageDecorator(message)
);
System.out.println("Encrypted & Compressed: " + encryptedAndCompressedMessage.getContent());
// 输出: "!egassemtercesasith,olleH"
}
}
2. Spring 中的装饰器思想实现
Spring 并没有直接使用传统的装饰器模式,但通过 AOP 和 代理模式 实现了类似的功能动态增强。
2.1 使用 AOP 实现日志装饰
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.MessageService.processMessage(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行原始方法
long executionTime = System.currentTimeMillis() - start;
System.out.println("方法耗时: " + executionTime + "ms");
return result;
}
}
2.2 使用 BeanPostProcessor 动态装饰 Bean
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MessageService) {
// 动态包装目标 Bean
return Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
new Class[]{MessageService.class},
(proxy, method, args) -> {
System.out.println("装饰器模式拦截方法: " + method.getName());
return method.invoke(bean, args); // 调用原始方法
});
}
return bean;
}
}
2.3 Spring Security 的装饰器思想
Spring Security 的 FilterChain 类似责任链 + 装饰器模式:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new CustomAuthFilter(), UsernamePasswordAuthenticationFilter.class); // 类似装饰器添加新功能
return http.build();
}
}
3. 两种实现对比
| 方式 | 优点 | 缺点 |
|---|---|---|
| 传统装饰器模式 | 显式控制装饰逻辑,适合业务层扩展 | 需要手动编写装饰器类 |
| Spring AOP | 与框架集成,适合非业务逻辑(日志、事务) | 仅适用于 Spring 管理的 Bean |
4. 总结
- 传统装饰器模式:适用于业务逻辑的动态增强(如消息处理、UI 组件扩展)。
- Spring AOP:更适合系统级功能(日志、安全、缓存),通过注解和配置实现无侵入性增强。
如果需要更具体的场景(如在 Spring Boot 中实现某个业务功能的装饰),可以提供需求细节,我会进一步补充代码示例。
四、装饰器模式 vs 代理模式 vs 适配器模式
- 装饰器模式:当你需要在运行时动态地为对象添加功能,并希望保持代码灵活性和可扩展性。
- 代理模式:当你需要控制对某个对象的访问,比如进行权限检查、日志记录、缓存等。
- 适配器模式:当你需要整合两个不兼容接口的类,使其能一起工作,而不想修改现有代码。
五、总结
- 装饰器模式适用于需要在运行时动态增强对象行为的场景。
- Spring 中虽未直接使用装饰器,但其 AOP、BeanPostProcessor、Security 过滤链等机制都体现了其思想。
- 它是构建灵活、可扩展系统的重要手段之一。
- 如果你有具体的业务需求,比如“如何在 Spring 中为某个服务动态添加日志、缓存等功能”,我可以为你展示具体的代码示例。