装饰器模式是结构性设计模式中的一种,结构型设计模式主要总结了一些将类或接口组合在一起的经典结构,装饰器模式用于对现有的类的功能进行增强。
Java IO 中的装饰器模式
Java IO 中的类是装饰器模式的经典使用。为了读取文件中的内容,我们经常会使用如下的代码。
try (BufferedReader bis = new BufferedReader(new FileReader(new File("/Users/hkp/abc.txt")))) { String content = null; while ((content = bis.readLine()) != null) { System.out.println(content); } }
BufferedReader 作为一个装饰器类对 Reader 类进行了增强,提供了缓存字符的能力。
考虑一个问题,BufferedReader 构造方法需要 Reader 作为参数,为什么 Java 不提供一个 BufferedFileReader 类继承 FileReader 类呢?这是因为 Reader 除了 FileReader 还有其他众多的实现类,每个实现类除了缓存可能还需要进行其他增强,如果把增强的功能进行组合创建新的类,这将导致 Java IO 中类的数量呈倍数增加。
通过将继承关系改为组合关系能够有效解决类的继承结构过于复杂的问题。
如何实现一个装饰器模式
BufferedReader 类结构大致如下。
public class BufferedReader extends Reader { private Reader in; private char cb[]; private int nChars, nextChar; private static int defaultCharBufferSize = 8192; public BufferedReader(Reader in, int sz) { super(in); if (sz <= 0) throw new IllegalArgumentException("Buffer size <= 0"); this.in = in; cb = new char[sz]; nextChar = nChars = 0; } public BufferedReader(Reader in) { this(in, defaultCharBufferSize); } public int read() throws IOException { // 缓存增强 } }
BufferedReader 实现了 Reader 接口,并将原始 Reader 接口作为构造方法的参数,利用原始 Reader 实现接口中的方法,并在此基础上增加了缓存能力。
总结实现装饰器模式的步骤如下。
实现接口 InterF。
将接口 InterF 作为构造方法参数,保存为成员变量 target。
利用成员变量 target 实现接口 InterF 的方法,并增强其功能。
上述步骤中的接口如果为类则需要改成继承,其他保持一致。翻译上述实现装饰器的步骤为代码如下。
public interface InterF { void method1(); void method2(); } public class InterFDecorator implements InterF { private InterF target; public InterFDecorator(InterF target) { this.target = target; } @Override public void method1() { // 省略功能增强代码 target.method1(); // 省略功能增强代码 } @Override public void method2() { // 省略功能增强代码 target.method2(); // 省略功能增强代码 } }
总结
装饰器模式通过将继承关系转换为组合关系,解决了类的层次结构过于复杂的问题,对于原始类可以嵌套使用多个装饰器类。装饰器模式的实现与代理模式极为相似,不同的是代理模式为了实现与原始类不同的功能,而装饰器模式则用于对原有类的功能进行增强。