作者:Grey
原文地址:
装饰器模式是一种结构型模式。
顾名思义,就是对某个方法或者对象进行装饰,举个简单的例子,有个圆形类 Circle,我需要把这个圆形的涂上红色,其实就是新增一个装饰器来装饰这个圆形类。
如果要让装饰器通用一些,可以处理圆形类对应的抽象类 Sharp ,那么对于任意 Sharp 的子类,都可以用红色装饰器来涂红色。
示例代码如下
我们先定义 Sharp 这个抽象类
public abstract class Sharp {
protected abstract void draw();
}
然后我们定义 Sharp 的装饰类 SharpDecorator ,这个类是所有装饰器类的抽象类,后续的装饰器只需要实现这个抽象类就可以对 Sharp 进行各种装饰了,
public abstract class SharpDecorator extends Sharp {
protected Sharp decoratedSharp;
public SharpDecorator(Sharp decoratedSharp) {
this.decoratedSharp = decoratedSharp;
}
}
红色装饰器实现这个抽象类即可:
public class RedSharpDecorator extends SharpDecorator {
public RedSharpDecorator(Sharp decoratedSharp) {
super(decoratedSharp);
}
private static void redIt() {
System.out.println("[RED]");
}
@Override
protected void draw() {
redIt();
this.decoratedSharp.draw();
redIt();
}
}
主方法调用的时候只需要:
new RedSharpDecorator(new Circle()).draw();
UML 图如下:
说明:
装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。
装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。符合“组合关系”这种代码结构的设计模式有很多,比如代理模式、桥接模式,还有现在的装饰器模式。尽管它们的代码结构很相似,但是每种设计模式的意图是不同的。就拿比较相似的代理模式和装饰器模式来说:
代理模式中,代理类附加的是跟原始类无关的功能;
装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。
在 JDK 中,BufferedInputStream 、 DataInputStream 并非继承自 InputStream ,而是另外一个叫 FilterInputStream 的类。
这是因为 InputStream 是一个抽象类而非接口,而且它的大部分函数(比如 read()
、available()
)都有默认实现,按理来说,我们只需要在 BufferedInputStream 类中重新实现那些需要增加缓存功能的函数就可以了,其他函数只需要复用 InputStream 的默认实现。但实际上,这样做是行不通的。对于即便是不需要增加缓存功能的函数来说,BufferedInputStream 还是必须把它重新实现一遍,简单包裹对 InputStream 对象的函数调用。那 BufferedInputStream 类就无法将最终读取数据的任务,委托给传递进来的 InputStream 对象来完成,DataInputStream 也存在跟 BufferedInputStream 同样的问题。为了避免代码重复,Java I/O 包中抽象出了一个装饰器父类 FilterInputStream,包装了 InputStream 的默认实现
package java.io;
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
public int read() throws IOException {
return in.read();
}
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
}
public long skip(long n) throws IOException {
return in.skip(n);
}
public int available() throws IOException {
return in.available();
}
public void close() throws IOException {
in.close();
}
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}
public synchronized void reset() throws IOException {
in.reset();
}
public boolean markSupported() {
return in.markSupported();
}
}
InputStream 的所有的装饰器类( BufferedInputStream 和 DataInputStream )都继承自这个装饰器父类。这样,装饰器类只需要实现它需要增强的方法就可以了,其他方法继承装饰器父类的默认实现。
其他应用
Java 中的 I/O 流, Read/InputStream
,Write/OutputStream
;
Java 中的 UnmodifiableCollection
;
Spring 中的 HttpHeadResponseDecorator
, 还有对 Cache 的装饰类 TransactionAwareCacheDecorator
。