装饰器模式
引言
装饰器模式(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. 装饰器模式的优势
- 灵活性:可以动态组合功能,如缓冲+数据读取+行号跟踪
- 避免类爆炸:不需要为每种功能组合创建子类
- 开闭原则:不修改原有代码即可扩展功能
- 运行时配置:可以在运行时决定如何装饰对象
3. 装饰器模式的典型应用场景
- 添加缓冲功能 :
BufferedInputStream
/BufferedOutputStream
- 添加基本数据类型读写 :
DataInputStream
/DataOutputStream
- 添加行号跟踪 :
LineNumberReader
- 添加推回功能 :
PushbackInputStream
- 添加字符编码转换 :
InputStreamReader
/OutputStreamWriter
4. 使用注意事项
- 关闭流:只需要关闭最外层的装饰器,内层流会自动关闭
- 装饰顺序:装饰顺序有时会影响性能,如缓冲流应该尽可能靠近原始流
- 性能考虑:过多的装饰层会增加方法调用开销
与继承方式的对比
假设不使用装饰器模式,要为文件流添加缓冲和数据读取功能,可能需要:
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 般动态可扩展的架构,让功能组合如艺术般流畅。
(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢