装饰器模式详解

以下是一个结合装饰器模式解决实际开发问题的Java实现案例,涵盖动态扩展功能、多层装饰顺序控制、性能优化等场景需求,附带逐行中文注释:

场景描述

开发一个数据加密传输系统,需满足:

基础功能:原始数据传输

加密扩展:支持AES、Base64、GZIP等加密/压缩组合

动态配置:运行时自由组合加密流程(如AES→GZIP→Base64)

性能监控:统计加密过程耗时

顺序控制:防止重复包装(如多次AES加密)

完整代码实现

java 复制代码
import java.util.*;

/**
 * 数据处理器抽象接口(Component)
 */
interface DataProcessor {
    // 处理数据
    byte[] process(byte[] data) throws Exception;
    
    // 获取当前处理类型(用于顺序校验)
    String getProcessorType();
}

/**
 * 基础实现:原始数据传输(ConcreteComponent)
 */
class RawDataProcessor implements DataProcessor {
    @Override
    public byte[] process(byte[] data) {
        System.out.println("传输原始数据,大小:" + data.length + "字节");
        return data;
    }

    @Override
    public 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;
    }

    @Override
    public String getProcessorType() {
        return type;
    }
}

// ------------------- 具体装饰器实现 -------------------

/**
 * AES加密装饰器(ConcreteDecorator)
 */
class AESEncryptor extends EncryptionDecorator {
    public AESEncryptor(DataProcessor processor) {
        super(processor, "AES");
    }

    @Override
    public 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");
    }

    @Override
    public 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");
    }

    @Override
    public 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;
    }

    @Override
    public byte[] process(byte[] data) throws Exception {
        long start = System.nanoTime();
        byte[] result = wrapped.process(data);
        processTime = System.nanoTime() - start;
        return result;
    }

    @Override
    public 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控制添加顺序,构造函数校验重复类型
性能监控困难 - 添加非侵入式监控装饰器
代码侵入性高 - 核心类保持纯净,扩展功能通过装饰器实现
维护成本高 - 每个装饰器独立维护,符合单一职责原则
多层嵌套调试困难- 为每个装饰器添加日志输出,清晰展示处理流程

装饰器模式优势分析

动态扩展能力

java 复制代码
// 运行时自由组合加密流程
DataProcessor p1 = new AESEncryptor(new GZIPCompressor(new RawDataProcessor()));
DataProcessor p2 = new Base64Encoder(new AESEncryptor(new RawDataProcessor()));

符合开闭原则

新增功能:只需添加新的装饰器类

原有代码:无需修改核心组件和已有装饰器

替代多重继承

text 复制代码
传统继承方式:
AES_GZIP_Processor
AES_Base64_Processor
GZIP_Base64_Processor
...

装饰器模式:

AESEncryptor → GZIPCompressor → Base64Encoder

职责清晰分离

每个装饰器只关注单一功能

业务逻辑与基础设施分离(如加密算法与性能监控)

性能优化技巧

缓存装饰器实例

java 复制代码
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));
    }
}

异步处理装饰器

java 复制代码
class AsyncDecorator implements DataProcessor {
    private final Executor executor = Executors.newCachedThreadPool();
    
    public byte[] process(byte[] data) {
        executor.execute(() -> wrapped.process(data));
        return data; // 立即返回,异步处理
    }
}

批量处理优化

java 复制代码
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流体系

java 复制代码
InputStream in = new BufferedInputStream(
                 new GZIPInputStream(
                 new FileInputStream("data.gz")));

Web中间件

java 复制代码
HttpServletRequest wrappedRequest = new LoggingRequestWrapper(
                                   new CachingRequestWrapper(
                                   new XSSFilterWrapper(rawRequest)));

游戏装备系

java 复制代码
Weapon weapon = new LaserSight(
                new ExtendedMagazine(
                new BaseRifle()));

通过这个案例可以看出,装饰器模式在需要动态增强对象功能且要求扩展灵活的场景中表现优异。实际开发中建议:

控制装饰层数:避免过度嵌套影响性能

明确装饰顺序:通过Builder等模式管理

注意对象标识:装饰后会改变对象hashCode/equals行为

结合其他模式:如工厂模式创建装饰器链

一句话总结

装饰器模式是通过组合的方式将一个实现了共同接口或抽象类的对象进行包装,并在执行时按照装饰的顺序进行递归调用,以实现功能的动态扩展。

相关推荐
小张学Python3 分钟前
AI数字人Heygem:口播与唇形同步的福音,无需docker,无需配置环境,一键整合包来了
python·数字人·heygem
跳跳糖炒酸奶7 分钟前
第四章、Isaacsim在GUI中构建机器人(2):组装一个简单的机器人
人工智能·python·算法·ubuntu·机器人
桃子酱紫君23 分钟前
华为配置篇-BGP实验
开发语言·华为·php
步木木34 分钟前
Anaconda和Pycharm的区别,以及如何选择两者
ide·python·pycharm
QTX1873035 分钟前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
星始流年36 分钟前
解决PyInstaller打包PySide6+QML应用的资源文件问题
python·llm·pyspider
南玖yy38 分钟前
Python网络爬虫:从入门到实践
爬虫·python
shaoing38 分钟前
MySQL 错误 报错:Table ‘performance_schema.session_variables’ Doesn’t Exist
java·开发语言·数据库
The Future is mine1 小时前
Python计算经纬度两点之间距离
开发语言·python
Enti7c1 小时前
HTML5和CSS3的一些特性
开发语言·css3