上一篇说到适配器模式,这次说它的同胞兄弟——装饰器模式。我们有时会遇到需要对类自身方法功能的累加,比如FilterInputStream需要InputStream其他子类的read上累加功能。


  • 举例

装饰器通常需要一个源,即你认为需要包装或基于此添加功能的类,源需要与装饰器同父类。

如下代码,源DecoratorTargetSource被实例化时并不需要传入任何DecoratorTarget类型,而Decorator1Decorator2Decorator3等装饰类实例化时需要DecoratorTarget类型对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//基类(接口)
public interface DecoratorTarget {
void read(byte[] bs);
}
//源基类
public class DecoratorTargetSource implements DecoratorTarget {
@Override
public void read(byte[] bs) {}
}
//源基类装饰器1
public class Decorator1 implements DecoratorTarget {
protected DecoratorTarget target;
public Decorator1(DecoratorTarget target) {
this.target = target;
}
@Override
public void read(byte[] bs) {
// ...
target.read(bs);
// ...
}
}
//源基类装饰器2
public class Decorator2 implements DecoratorTarget {
protected DecoratorTarget target;
public Decorator2(DecoratorTarget target) {
this.target = target;
}
@Override
public void read(byte[] bs) {
// ...
target.read(bs);
// ...
}
}
//源基类装饰器3
public class Decorator3 extends Decorator1 {
public Decorator3(DecoratorTarget target) {
super(target);
this.target = target;
}
@Override
public void read(byte[] bs) {
// ...
target.read(bs);
// ...
}
}
public class DecoratorTemplate {
public static void main(String[] args) {
DecoratorTarget target = new Decorator1(new Decorator3(new Decorator2(new DecoratorTargetSource())));
}
}
  • JDK中的装饰器模式

Java中最为人所知的装饰器模式,莫过于IO框架。源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//基类
public abstract class InputStream implements Closeable {
//...
}
//装饰器FilterInputStream
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
}
//装饰器BufferedInputStream,继承于FilterInputStream
public class BufferedInputStream extends FilterInputStream {
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
private void fill() throws IOException {
// ...
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
// ...
}
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
}
//源
public class FileInputStream extends InputStream {
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
fd = new FileDescriptor();
fd.incrementAndGetUseCount();
this.path = name;
open(name);
}
public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager();
if (fdObj == null) {
throw new NullPointerException();
}
if (security != null) {
security.checkRead(fdObj);
}
fd = fdObj;
path = null;
fd.incrementAndGetUseCount();
}
}

上述源码中,FileInputStream并没有参数包含InputStream类型,所以可以看成是一个源,那么FilterInputStream及其子类BufferedInputStream则是装饰器。