以下是一个结合装饰器模式解决实际开发问题的Java实现案例,涵盖动态扩展功能、多层装饰顺序控制、性能优化等场景需求,附带逐行中文注释:
场景描述
开发一个数据加密传输系统,需满足:
基础功能:原始数据传输
加密扩展:支持AES、Base64、GZIP等加密/压缩组合
动态配置:运行时自由组合加密流程(如AES→GZIP→Base64)
性能监控:统计加密过程耗时
顺序控制:防止重复包装(如多次AES加密)
完整代码实现
import java.util.*;/*** 数据处理器抽象接口(Component)*/
interface DataProcessor {// 处理数据byte[] process(byte[] data) throws Exception;// 获取当前处理类型(用于顺序校验)String getProcessorType();
}/*** 基础实现:原始数据传输(ConcreteComponent)*/
class RawDataProcessor implements DataProcessor {@Overridepublic byte[] process(byte[] data) {System.out.println("传输原始数据,大小:" + data.length + "字节");return data;}@Overridepublic String getProcessorType() {return "RAW";}
}/*** 加密装饰器抽象类(Decorator)*/
abstract class EncryptionDecorator implements DataProcessor {protected final DataProcessor wrapped;private final String type;//这个type不推荐自己装饰使用,耦合度以及复杂度太大,需要开发人员自己保证装饰器不重复,重复了也正常执行。//并且如果A装饰B,B装饰C就不能约束住代码了。protected EncryptionDecorator(DataProcessor wrapped, String type) { this.wrapped = validateWrapped(wrapped, type);this.type = type;}// 装饰顺序校验:防止重复包装同类处理器private DataProcessor validateWrapped(DataProcessor processor, String newType) {if (processor.getProcessorType().equals(newType)) {throw new IllegalArgumentException("禁止重复添加" + newType + "处理器");}return processor;}@Overridepublic String getProcessorType() {return type;}
}// ------------------- 具体装饰器实现 -------------------/*** AES加密装饰器(ConcreteDecorator)*/
class AESEncryptor extends EncryptionDecorator {public AESEncryptor(DataProcessor processor) {super(processor, "AES");}@Overridepublic byte[] process(byte[] data) throws Exception {System.out.println("【AES加密】输入数据大小:" + data.length + "字节");byte[] processed = wrapped.process(data);// 模拟AES加密(实际应使用加密库)byte[] encrypted = Arrays.copyOf(processed, processed.length + 16); // +16模拟加密后长度System.out.println("【AES加密】输出数据大小:" + encrypted.length + "字节");return encrypted;}
}/*** Base64编码装饰器(ConcreteDecorator)*/
class Base64Encoder extends EncryptionDecorator {public Base64Encoder(DataProcessor processor) {super(processor, "BASE64");}@Overridepublic byte[] process(byte[] data) throws Exception {System.out.println("【Base64编码】输入数据大小:" + data.length + "字节");byte[] processed = wrapped.process(data);// 模拟Base64编码(实际应使用Base64库)String encoded = new String(processed) + "_base64";System.out.println("【Base64编码】输出数据大小:" + encoded.length() + "字节");return encoded.getBytes();}
}/*** GZIP压缩装饰器(ConcreteDecorator)*/
class GZIPCompressor extends EncryptionDecorator {public GZIPCompressor(DataProcessor processor) {super(processor, "GZIP");}@Overridepublic byte[] process(byte[] data) throws Exception {System.out.println("【GZIP压缩】输入数据大小:" + data.length + "字节");byte[] processed = wrapped.process(data);// 模拟压缩(实际应使用GZIP库)byte[] compressed = Arrays.copyOfRange(processed, 0, processed.length / 2);System.out.println("【GZIP压缩】输出数据大小:" + compressed.length + "字节");return compressed;}
}/*** 监控装饰器(扩展功能)*/
class MonitoringDecorator implements DataProcessor {private final DataProcessor wrapped;private long processTime;public MonitoringDecorator(DataProcessor processor) {this.wrapped = processor;}@Overridepublic byte[] process(byte[] data) throws Exception {long start = System.nanoTime();byte[] result = wrapped.process(data);processTime = System.nanoTime() - start;return result;}@Overridepublic String getProcessorType() {return "MONITOR";}public long getProcessTime() {return processTime;}
}// ------------------- 装饰器工厂(解决顺序问题) -------------------
// 建造者模式,这里其实也可以拓展一个抽象工厂,不过会使复杂度几何增加
//如果当前以及未来设计装饰产品族不够多的情况下建议不适用工厂
class ProcessorBuilder {private DataProcessor processor;private final Set<String> addedTypes = new HashSet<>();public ProcessorBuilder(DataProcessor baseProcessor) {this.processor = baseProcessor;addedTypes.add(baseProcessor.getProcessorType());}public ProcessorBuilder addAES() {return addDecorator(new AESEncryptor(processor), "AES");}public ProcessorBuilder addBase64() {return addDecorator(new Base64Encoder(processor), "BASE64");}public ProcessorBuilder addGZIP() {return addDecorator(new GZIPCompressor(processor), "GZIP");}public ProcessorBuilder addMonitoring() {return addDecorator(new MonitoringDecorator(processor), "MONITOR");}private ProcessorBuilder addDecorator(DataProcessor decorator, String type) {if (!addedTypes.add(type)) {throw new IllegalStateException(type + "处理器已存在");}this.processor = decorator;return this;}public DataProcessor build() {return processor;}
}// ------------------- 客户端代码 -------------------
public class DecoratorPatternDemo {public static void main(String[] args) throws Exception {// 构建处理链:原始数据 → AES → GZIP → Base64 → 监控DataProcessor processor = new ProcessorBuilder(new RawDataProcessor()).addAES().addGZIP().addBase64().addMonitoring().build();// 测试数据处理byte[] originalData = "Hello Decorator Pattern!".getBytes();byte[] result = processor.process(originalData);// 获取监控数据,这里能成功的原因是因为最后加入Monitoring,数据类型变成这种if (processor instanceof MonitoringDecorator) {long nanos = ((MonitoringDecorator) processor).getProcessTime();System.out.printf("\n处理耗时:%.2f ms", nanos / 1_000_000.0);}// 测试异常情况:重复添加处理器try {new ProcessorBuilder(new RawDataProcessor()).addAES().addAES(); // 触发重复添加异常} catch (IllegalStateException e) {System.out.println("\n异常捕获:" + e.getMessage());}}
}
真实场景问题解决
问题类型 | 解决方案 |
---|---|
功能组合爆炸 - | 动态组合装饰器,避免继承导致的类膨胀 |
装饰顺序敏感 - | 通过Builder控制添加顺序,构造函数校验重复类型 |
性能监控困难 - | 添加非侵入式监控装饰器 |
代码侵入性高 - | 核心类保持纯净,扩展功能通过装饰器实现 |
维护成本高 - | 每个装饰器独立维护,符合单一职责原则 |
多层嵌套调试困难- | 为每个装饰器添加日志输出,清晰展示处理流程 |
装饰器模式优势分析
动态扩展能力
// 运行时自由组合加密流程
DataProcessor p1 = new AESEncryptor(new GZIPCompressor(new RawDataProcessor()));
DataProcessor p2 = new Base64Encoder(new AESEncryptor(new RawDataProcessor()));
符合开闭原则
新增功能:只需添加新的装饰器类
原有代码:无需修改核心组件和已有装饰器
替代多重继承
传统继承方式:
AES_GZIP_Processor
AES_Base64_Processor
GZIP_Base64_Processor
...
装饰器模式:
AESEncryptor → GZIPCompressor → Base64Encoder
职责清晰分离
每个装饰器只关注单一功能
业务逻辑与基础设施分离(如加密算法与性能监控)
性能优化技巧
缓存装饰器实例
class DecoratorCache {private static Map<String, DataProcessor> cache = new ConcurrentHashMap<>();public static DataProcessor getDecorator(DataProcessor base, String type) {String key = base.hashCode() + "_" + type;return cache.computeIfAbsent(key, k -> createDecorator(base, type));}
}
异步处理装饰器
class AsyncDecorator implements DataProcessor {private final Executor executor = Executors.newCachedThreadPool();public byte[] process(byte[] data) {executor.execute(() -> wrapped.process(data));return data; // 立即返回,异步处理}
}
批量处理优化
class BatchDecorator implements DataProcessor {public byte[] process(byte[] data) {// 将大数据拆分为块处理byte[][] chunks = splitData(data);Arrays.parallelSetAll(chunks, i -> wrapped.process(chunks[i]));return combineChunks(chunks);}
}
模式对比
模式 | 核心思想 | 装饰器模式特点 |
---|---|---|
适配器模式 | 接口转换 | 不改变接口,只增强功能 |
代理模式 | 控制访问 | 透明增强,客户端无感知 |
策略模式 | 算法替换 | 动态叠加算法而非替换 |
组合模式 | 树形结构 | 装饰器链是线性结构 |
行业应用案例
Java IO流体系
InputStream in = new BufferedInputStream(new GZIPInputStream(new FileInputStream("data.gz")));
Web中间件
HttpServletRequest wrappedRequest = new LoggingRequestWrapper(new CachingRequestWrapper(new XSSFilterWrapper(rawRequest)));
游戏装备系
Weapon weapon = new LaserSight(new ExtendedMagazine(new BaseRifle()));
通过这个案例可以看出,装饰器模式在需要动态增强对象功能且要求扩展灵活的场景中表现优异。实际开发中建议:
控制装饰层数:避免过度嵌套影响性能
明确装饰顺序:通过Builder等模式管理
注意对象标识:装饰后会改变对象hashCode/equals行为
结合其他模式:如工厂模式创建装饰器链
一句话总结
装饰器模式是通过组合的方式将一个实现了共同接口或抽象类的对象进行包装,并在执行时按照装饰的顺序进行递归调用,以实现功能的动态扩展。