Administrator
Published on 2025-04-25 / 13 Visits
0
0

以 ​​云存储文件上传​​ 场景为例简单展示装饰器模式优势

以下以 ​​云存储文件上传​​ 场景为例,展示如何通过装饰器模式实现 ​​基础文件上传 + 加密 + 压缩 + 日志记录​​ 的灵活组合,并与传统实现方式对比

装饰器模式实现

1. 核心接口定义

public interface FileUploader {
    void upload(String filePath);
}

2. 基础上传实现

@Component
public class BasicFileUploader implements FileUploader {
    @Override
    public void upload(String filePath) {
        System.out.println("[核心逻辑] 上传文件到云存储: " + filePath);
    }
}

3. 装饰器抽象类

public abstract class FileUploadDecorator implements FileUploader {
    protected final FileUploader wrapped;

    public FileUploadDecorator(FileUploader uploader) {
        this.wrapped = uploader;
    }

    @Override
    public abstract void upload(String filePath);
}

4. 具体装饰器实现

// 加密装饰器
@Component
public class EncryptUploadDecorator extends FileUploadDecorator {
    public EncryptUploadDecorator(FileUploader uploader) {
        super(uploader);
    }

    @Override
    public void upload(String filePath) {
        String encryptedFile = encrypt(filePath);
        wrapped.upload(encryptedFile);
    }

    private String encrypt(String filePath) {
        System.out.println(">>> 加密文件: " + filePath);
        return filePath + ".enc";
    }
}

// 压缩装饰器
@Component
public class CompressUploadDecorator extends FileUploadDecorator {
    public CompressUploadDecorator(FileUploader uploader) {
        super(uploader);
    }

    @Override
    public void upload(String filePath) {
        String compressedFile = compress(filePath);
        wrapped.upload(compressedFile);
    }

    private String compress(String filePath) {
        System.out.println(">>> 压缩文件: " + filePath);
        return filePath + ".zip";
    }
}

// 日志记录装饰器
@Component
public class LoggingUploadDecorator extends FileUploadDecorator {
    public LoggingUploadDecorator(FileUploader uploader) {
        super(uploader);
    }

    @Override
    public void upload(String filePath) {
        System.out.println("【开始上传】" + LocalDateTime.now());
        wrapped.upload(filePath);
        System.out.println("【上传完成】" + LocalDateTime.now());
    }
}

5. 组合装饰器(通过Spring配置)

@Configuration
public class UploadConfig {
    
    @Bean("secureUploader")
    public FileUploader buildSecureUploader(
        BasicFileUploader base,
        EncryptUploadDecorator encrypt,
        CompressUploadDecorator compress) {
        // 组合顺序:加密 → 压缩 → 基础上传
        return new EncryptUploadDecorator(
            new CompressUploadDecorator(base)
        );
    }

    @Bean("fullFeatureUploader")
    public FileUploader buildFullFeatureUploader(
        BasicFileUploader base,
        EncryptUploadDecorator encrypt,
        CompressUploadDecorator compress,
        LoggingUploadDecorator logging) {
        // 组合顺序:日志 → 加密 → 压缩 → 基础上传
        return new LoggingUploadDecorator(
            new EncryptUploadDecorator(
                new CompressUploadDecorator(base)
            )
        );
    }
}

6. 对外暴露接口

@RestController
public class FileController {
    @Autowired
    @Qualifier("fullFeatureUploader") // 注入组合后的装饰器
    private FileUploader fileUploader;

    @PostMapping("/upload")
    public String uploadFile(@RequestParam String filePath) {
        fileUploader.upload(filePath);
        return "文件处理完成";
    }
}

传统方式实现

@Service
public class TraditionalFileUploader {
    
    public void upload(String filePath, 
                      boolean needEncrypt, 
                      boolean needCompress,
                      boolean enableLogging) {
        String processedFile = filePath;

        if (enableLogging) {
            System.out.println("【开始上传】" + LocalDateTime.now());
        }

        if (needEncrypt) {
            System.out.println(">>> 加密文件: " + processedFile);
            processedFile += ".enc";
        }

        if (needCompress) {
            System.out.println(">>> 压缩文件: " + processedFile);
            processedFile += ".zip";
        }

        System.out.println("[核心逻辑] 上传文件到云存储: " + processedFile);

        if (enableLogging) {
            System.out.println("【上传完成】" + LocalDateTime.now());
        }
    }
}

两种方式对比分析

1. 执行效果对比

​请求示例:​

POST /upload?filePath=report.pdf

​装饰器模式输出:​

【开始上传】2023-08-20T14:30:00.123
>>> 加密文件: report.pdf
>>> 压缩文件: report.pdf.enc
[核心逻辑] 上传文件到云存储: report.pdf.enc.zip
【上传完成】2023-08-20T14:30:02.456

​传统方式输出(参数全true):​
(输出结果相同,但实现方式完全不同)

2. 核心差异点

​​维度​​

​​装饰器模式​​

​​传统方式​​

​功能扩展​

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

必须修改原方法,添加新条件判断

​组合灵活性​

运行时动态调整装饰顺序

组合顺序硬编码,修改需要调整代码顺序

​职责划分​

每个装饰器独立处理单一职责

所有逻辑混杂在同一个方法中

​单元测试​

可单独测试每个装饰器

需要覆盖大量条件分支组合

​配置管理​

通过@Bean配置不同组合

通过参数控制,调用方需要了解细节

​代码可读性​

每个功能模块独立,结构清晰

方法可能超长,可读性随功能增加下降

3. 装饰器模式核心优势

  1. ​符合开闭原则​
    新增文件水印功能只需创建 WatermarkDecorator,无需触碰已有代码:

    @Component
    public class WatermarkDecorator extends FileUploadDecorator {
        // 实现水印功能
    }
  2. ​动态组合能力​
    根据不同场景配置不同处理流程:

    // 敏感文件处理流:加密 → 水印 → 上传
    new WatermarkDecorator(
        new EncryptUploadDecorator(base)
    )
    
    // 大文件处理流:压缩 → 分片 → 上传
    new ChunkDecorator(
        new CompressUploadDecorator(base)
    )
  3. ​功能复用便捷​
    同一装饰器可被多个流程复用:

    // 日志装饰器可应用于上传、下载等不同场景
    public class LoggingDownloadDecorator extends DownloadDecorator {
        // 复用相同的日志逻辑
    }
  4. ​与AOP无缝整合​
    结合Spring AOP实现更强大的切面控制:

    @Around("execution(* com.example.upload.*.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) {
        // 在装饰器基础上增加统一监控
    }

适用场景推荐

  1. ​金融交易流水线​​:交易验证 → 风控检查 → 记账 → 通知

  2. ​多媒体处理​​:视频转码 → 添加字幕 → 画质增强

  3. ​物联网数据处理​​:数据清洗 → 异常检测 → 聚合分析

  4. ​API网关​​:鉴权 → 限流 → 缓存 → 响应格式化

  5. ​电商订单流程​​:价格计算 → 库存锁定 → 支付 → 物流创建

装饰器模式的核心价值

通过​​动态包装​​替代​​静态继承​​,装饰器模式在以下场景展现独特优势:

  1. ​业务需求频繁变更​​:快速响应新增功能需求

  2. ​功能排列组合爆炸​​:避免创建大量子类

  3. ​核心逻辑需要保护​​:不改动基础代码的前提下增强功能

  4. ​系统可观测性建设​​:灵活添加监控、日志等非业务功能

当系统需要像"乐高积木"一样灵活组装功能模块时,装饰器模式是最优雅的解决方案之一。


Comment