一、意图与动机
动态的给一个对象而不是整个类添加一些额外的职责。
二、适用性
- 一下情况适合使用装饰器模式
- 不影响其它对象职责的情况下,动态、透明的各条单个对象添加职责
- 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持没有组组则将产生大量的子类,使得子类数目呈爆炸式增长。另一种情况是因为类定义被隐藏,或者类定义不能用于生成子类。
三、结构
四、实现
- 使用装饰器模式需要注意以下几点
- 接口一致性。装饰对象的接口必须与它装饰的对象的接口是一致的,因此,结构图中,CoreFunctionality和OptionalWrapper必须有一个公共的接口。
- 省略抽象的Decorator类,也就是结构图中的OptionalWrapper类。当仅仅需要添加一个职责时,没有必要定义抽象的Decorator类,直接在将请求转发的职责放到具体类中
- 保持基础接口的简单性。为了保持接口一致性,原始类和装饰类有一个公共的接口,保持这个公共接口的简单性很重要,否则CoreFunctionality会过于庞大和复杂。
- 改变对象外壳与改变对象内核。可以将Decorator看着一个对象的外壳,可以改变对象的行为而不是类。如果要改变对象的内核,策略模式是一种选择
五、案例
装饰器模式在java的IO库中大量使用,现抽取部分示例如下
public class BufferedReader extends Reader {
private Reader in;
private char cb[];
private int nChars, nextChar;
private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
private int markedChar = UNMARKED;
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
/** If the next character is a line feed, skip it */
private boolean skipLF = false;
/** The skipLF flag when the mark was set */
private boolean markedSkipLF = false;
// ......
}
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
/**
* Creates an InputStreamReader that uses the default charset.
*
* @param in An InputStream
*/
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
// ......
}
类似该例子,java io库中,还有很多使用装饰器模式的例子,如FilterReader、FilterWriter、BufferedWriter、PrintWriter、LineNumberReader、PushBackReader。