1. 装饰器模式概述
装饰器模式又叫装饰者模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。
(1) 适用情况
动态地给一个对象添加一些额外的职责。
(2) 优点
相比于生成子类更加灵活,减少了装饰者和被装饰者之间的耦合。
(3) 缺点
若装饰器过多,会使得系统变的复杂。
2. 装饰器模式实例
最常见的例子,就是I/O流。
Java中把不同的输入/输出源抽象为流,可以分为字节流和字符流。
字节流是把1个字节作为一个处理单元,主要用来处理byte类型的数据;
字符流是把2个字符作为一个处理单元,它是把编码集对字节流翻译之后的产物,用来处理中文等。
(1) 字节流
面向字节的输入流为InputStream,输出流为OutputStream;
但是它们都是抽象类,需要有对应的子类实现,比如用来处理文件的FileInputStream和FileOutputStream;
而BufferedInputStream和BufferedOutputStream可以为输入/输出流添加一些功能,比如提供缓冲功能,支持mark标记和reset重置方法等,这就是用到了装饰器模式的思想。
public class ByteStreamDemo {
public static void main(String[] args) {
try {
// 生成文件对象
File file = new File("D:/test.txt");
// 创建输出流
FileOutputStream fileOutputStream = new FileOutputStream(file);
// 创建缓冲输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
// 写数据
bufferedOutputStream.write("Hello World!".getBytes());
// 释放资源
bufferedOutputStream.close();
// 创建输入流
InputStream inputStream = new FileInputStream(file);
// 创建缓冲输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
// 读数据
int len;
while ((len = bufferedInputStream.read()) != -1) {
System.out.print((char) len);
}
// 释放资源
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2) 字符流
面向字符的输入流为Reader,输出流为Writer;
InputStreamReader和OutputStreamWriter可以将字节输入/输出流转化为字符输入/输出流;
BufferedReader和BufferedWriter提供了缓冲功能;
FileReader和FileWriter可以用来处理文件;
这都用到了装饰器模式的思想。
public class CharacterStreamDemo {
public static void main(String[] args) {
try {
// 生成文件对象
File file = new File("D:/hello.txt");
// 创建输出流
FileOutputStream fileOutputStream = new FileOutputStream(file);
// 字节流转为字符流
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
// 创建缓冲输出流
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
// 写数据
bufferedWriter.write("你好");
// 释放资源
bufferedWriter.close();
// 创建输入流
FileInputStream fileInputStream = new FileInputStream(file);
// 字节流转为字符流
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
// 创建缓冲输入流
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
// 读数据
String read;
while ((read = bufferedReader.readLine()) != null) {
System.out.print(read);
}
// 释放资源
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 一些思考
在适配器模式中,我们专门创建了适配器类,来调用被适配的类的方法。而在装饰器模式中,我们只是使用被装饰者来构造装饰者,这两者感觉确实很像。