Spring + 设计模式 (七) 结构型 - 装饰器模式

装饰器模式

引言

装饰器模式(Decorator Pattern)是一种结构型设计模式,核心在于动态地为对象添加新功能,而无需修改其原有代码。它通过包装现有对象,层层扩展行为,保持接口一致性,仿佛为对象披上"功能外衣"。装饰器模式强调灵活性和可扩展性,特别适合需要动态组合功能的场景,如日志记录、权限控制或数据过滤,优雅实现"开闭原则"。

实际开发中的用途

在实际开发中,装饰器模式广泛用于需要动态增强对象行为的场景,如Web应用的请求过滤、数据流的加密压缩或日志追踪。它解决了硬编码功能的紧耦合问题,允许运行时自由组合功能,提升代码复用性和可维护性。例如,在REST API中,装饰器可为响应添加认证、日志或格式化功能,无需更改核心业务逻辑,特别适合模块化、高扩展性的企业级系统。

开发中的示例

设想一个订单处理系统,核心功能是计算订单总价。现需动态添加折扣、税费或赠品逻辑。若直接修改订单类,代码将变得臃肿且难以维护。通过装饰器模式,可定义一个订单接口,核心订单类实现基本计算逻辑,再通过装饰器类动态添加折扣或税费功能。客户端只需组合所需装饰器,即可灵活生成不同功能的订单对象,保持代码清晰且易于扩展。

Spring 源码中的应用

CachingClientHttpRequestFactory 是Spring Web模块中用于增强ClientHttpRequestFactory的一个装饰器实现(Spring 5.x及以上版本)。它通过包装底层的ClientHttpRequestFactory(如SimpleClientHttpRequestFactory或HttpComponentsClientHttpRequestFactory),为HTTP请求添加缓存功能,从而减少重复请求,提高性能。

下面是个详细的例子

java 复制代码
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        // 创建底层的ClientHttpRequestFactory
        ClientHttpRequestFactory simpleFactory = new SimpleClientHttpRequestFactory();

        // 使用CachingClientHttpRequestFactory装饰
        CachingClientHttpRequestFactory cachingFactory = 
            new CachingClientHttpRequestFactory(simpleFactory);

        // 创建RestTemplate并注入装饰后的工厂
        return new RestTemplate(cachingFactory);
    }
}
@Service
public class ApiService {

    @Autowired
    private RestTemplate restTemplate;

    public String fetchPost(int postId) {
        String url = "https://api.disjfhjxkb.com:8080?postId=" + postId;
        return restTemplate.getForObject(url, String.class);
    }
}

@RestController
public class ApiController {

    @Autowired
    private ApiService apiService;

    @GetMapping("/post/{id}")
    public String getPost(@PathVariable int id) {
        return apiService.fetchPost(id);
    }
}

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这段代码体现了装饰器模式的核心价值:透明增强职责分离。在实际开发中,这种模式广泛用于性能优化、日志记录等场景

优点

  • 透明性:客户端使用装饰后的对象时,接口保持一致,无需修改调用代码。
  • 灵活性:可以动态添加或移除缓存功能。
  • 复用性:缓存逻辑与HTTP请求逻辑解耦,可应用于不同的请求工厂。

Java I/O系统的装饰器模式详解

装饰器模式(Decorator Pattern)是Java I/O系统中最重要的设计模式之一,它允许在不修改原有对象结构的情况下动态地扩展功能。

1. 装饰器模式在Java I/O中的实现原理

1. 基本结构

Java I/O中的装饰器模式遵循以下结构:

  • 抽象组件(Component) : InputStream/OutputStream(字节流) 或 Reader/Writer(字符流)
  • 具体组件(ConcreteComponent) : FileInputStream, FileOutputStream
  • 装饰器(Decorator) : FilterInputStream, FilterOutputStream
  • 具体装饰器(ConcreteDecorator) : BufferedInputStream, DataInputStream
2. 核心特点
  • 装饰器和被装饰对象实现相同的接口
  • 装饰器内部持有被装饰对象的引用
  • 可以在运行时动态添加功能

2. 具体代码演示

示例1:基本的装饰器使用
java 复制代码
import java.io.*;

public class DecoratorDemo {
    public static void main(String[] args) {
        try {
            // 1. 创建基础文件输入流(具体组件)
            InputStream fileStream = new FileInputStream("test.txt");
            
            // 2. 添加缓冲功能(第一次装饰)
            InputStream bufferedStream = new BufferedInputStream(fileStream);
            
            // 3. 添加数据读取功能(第二次装饰)
            DataInputStream dataStream = new DataInputStream(bufferedStream);
            
            // 使用装饰后的流读取数据
            int data = dataStream.readInt();
            System.out.println("读取的数据: " + data);
            
            // 关闭流(只需要关闭最外层的装饰器)
            dataStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
示例2:自定义装饰器实现
java 复制代码
import java.io.*;

// 自定义装饰器 - 将输入流转换为大写
class UpperCaseInputStream extends FilterInputStream {
    public UpperCaseInputStream(InputStream in) {
        super(in);
    }
    
    @Override
    public int read() throws IOException {
        int c = super.read();
        return (c == -1) ? c : Character.toUpperCase((char)c);
    }
    
    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int result = super.read(b, off, len);
        for (int i = off; i < off + result; i++) {
            b[i] = (byte)Character.toUpperCase((char)b[i]);
        }
        return result;
    }
}

public class CustomDecoratorDemo {
    public static void main(String[] args) {
        try {
            String text = "hello, decorator pattern!";
            
            // 创建字节数组输入流
            InputStream in = new ByteArrayInputStream(text.getBytes());
            
            // 使用自定义装饰器
            InputStream upperIn = new UpperCaseInputStream(in);
            
            // 读取并打印装饰后的数据
            int c;
            while ((c = upperIn.read()) != -1) {
                System.out.print((char)c);
            }
            
            upperIn.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

装饰器模式的详细说明

1. Java I/O中装饰器类的关系

scss 复制代码
InputStream (抽象组件)
├── FileInputStream (具体组件)
├── FilterInputStream (抽象装饰器)
│   ├── BufferedInputStream (具体装饰器)
│   ├── DataInputStream (具体装饰器)
│   ├── PushbackInputStream (具体装饰器)
│   └── ...其他装饰器
└── ...其他具体组件

2. 装饰器模式的优势

  1. 灵活性:可以动态组合功能,如缓冲+数据读取+行号跟踪
  2. 避免类爆炸:不需要为每种功能组合创建子类
  3. 开闭原则:不修改原有代码即可扩展功能
  4. 运行时配置:可以在运行时决定如何装饰对象

3. 装饰器模式的典型应用场景

  1. 添加缓冲功能BufferedInputStream/BufferedOutputStream
  2. 添加基本数据类型读写DataInputStream/DataOutputStream
  3. 添加行号跟踪LineNumberReader
  4. 添加推回功能PushbackInputStream
  5. 添加字符编码转换InputStreamReader/OutputStreamWriter

4. 使用注意事项

  1. 关闭流:只需要关闭最外层的装饰器,内层流会自动关闭
  2. 装饰顺序:装饰顺序有时会影响性能,如缓冲流应该尽可能靠近原始流
  3. 性能考虑:过多的装饰层会增加方法调用开销

与继承方式的对比

假设不使用装饰器模式,要为文件流添加缓冲和数据读取功能,可能需要:

java 复制代码
class BufferedFileInputStream extends FileInputStream {...}
class DataBufferedFileInputStream extends BufferedFileInputStream {...}
class BufferedDataFileInputStream extends DataFileInputStream {...}
// 组合爆炸...

而使用装饰器模式,只需要:

java 复制代码
InputStream in = new DataInputStream(
                 new BufferedInputStream(
                 new FileInputStream("file.txt")));

这种组合方式明显更加灵活和可维护。

Java I/O系统中的装饰器模式通过灵活的包装机制,使得各种流处理功能可以像"俄罗斯套娃"一样层层叠加,既保持了类的单一职责原则,又提供了无限的功能组合可能性。理解这一模式对于高效使用Java I/O系统至关重要。

总结

装饰器模式如同一件裁剪精良的"功能外套",动态为对象披上新能力,既优雅又灵活。在 Spring 中,HandlerExecutionChain 通过装饰器模式实现请求的动态增强,赋予框架强大的扩展性。结合 Spring Boot,开发者可轻松构建高内聚、低耦合的系统,应对复杂需求。掌握装饰器模式,不仅能写出模块化的代码,更能设计出如 Spring 般动态可扩展的架构,让功能组合如艺术般流畅。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢

相关推荐
hello_ejb31 分钟前
聊聊Spring AI Alibaba的FeiShuDocumentReader
人工智能·python·spring
一只鹿鹿鹿1 小时前
【测试文档】项目测试文档,测试管理规程,测试计划,测试文档模版,软件测试报告书(Word)
数据库·后端·spring·单元测试
千千寰宇1 小时前
[设计模式/Java] 设计模式之门面模式(外观模式)【20】
设计模式
jstart千语1 小时前
【SpringBoot】HttpServletRequest获取使用及失效问题(包含@Async异步执行方案)
java·前端·spring boot·后端·spring
王有品2 小时前
Spring MVC 核心注解与文件上传教程
java·spring·mvc
ApeAssistant3 小时前
Spring + 设计模式 (八) 结构型 - 外观模式
spring·设计模式
Sc Turing3 小时前
Spring中的AOP基础理解
java·spring
都叫我大帅哥3 小时前
代码界的「万能前台」:门面模式的调停艺术
java·后端·设计模式