设计模式之装饰者模式
目录
- 定义
- 结构
- 适用场景
- 使用示例
定义
装饰者模式是一种结构型设计模式,它通过将对象放入包含行为的特殊封装对象中,从而动态地为原对象添加新功能。
结构
适用场景
1)动态扩展功能
需要在运行时为对象灵活添加或撤销功能,且这些功能可自由组合。
例如:为咖啡动态添加牛奶、糖、摩卡等配料。
2)避免继承爆炸
当子类数量过多(如 MilkCoffee、SugarCoffee、MilkSugarCoffee…)时,装饰者模式提供更优雅的扩展方案。
3)不可修改原对象代码
当无法修改原对象代码(如第三方库的类),但需扩展其行为时。
4)多层次功能叠加
功能需要按不同顺序组合(如先加糖再加牛奶 vs 先加牛奶再加糖)。
使用示例
以下是装饰者模式在IO中的简化示例。
定义抽象组件
import java.io.IOException;/*** 抽象组件*/
public interface InputStream {int read() throws IOException;void close() throws IOException;}
定义具体组件
import java.io.IOException;public class FileInputStream implements InputStream {private String filename;public FileInputStream(String filename) {this.filename = filename;}@Overridepublic int read() throws IOException {System.out.println("从文件" + filename + "读取字节");return 0; // 模拟返回字节}@Overridepublic void close() throws IOException {System.out.println("关闭文件" + filename);}
}
定义抽象装饰者
import java.io.IOException;/*** 抽象装饰者*/
public abstract class FilterInputStream implements InputStream {protected InputStream wrappee;public FilterInputStream(InputStream in) {this.wrappee = in;}@Overridepublic abstract int read() throws IOException;@Overridepublic void close() throws IOException {wrappee.close();}
}
定义具体装饰者
import java.io.IOException;/*** 具体装饰者A*/
public class BufferedInputStream extends FilterInputStream {public BufferedInputStream(InputStream in) {super(in);}@Overridepublic int read() throws IOException {System.out.println("从缓冲区读取字节");return wrappee.read();}
}
import java.io.IOException;/*** 具体装饰者B*/
public class DataInputStream extends FilterInputStream {public DataInputStream(InputStream in) {super(in);}@Overridepublic int read() throws IOException {System.out.println("读取并转换数据类型");return wrappee.read();}public String readUTF() throws IOException {return "装饰后的字符串数据";}
}
测试
import java.io.IOException;public class Client {public static void main(String[] args) throws IOException {InputStream in = new FileInputStream("test.txt");in = new BufferedInputStream(in);in = new DataInputStream(in);in.read();System.out.println(((DataInputStream) in).readUTF());in.close();}}