有时候为了传承某个类的一些功能,我们可以采用继承该类来获取功能,并可以通过覆写某些方法来进行功能加强。然而若想对一批类的功能进行加强,如果仍采用继承,不仅在代码上重复,并且不利于扩展。如下所示:
接口Component有一个fun()方法,ConcreteAComponent、ConcreteBComponent都实现了该接口,完成了fun方法。现在的需求是,想对ConcreteAComponent、ConcreteBComponent所实现的fun方法进行加强,如想计算出fun方法所花费时间、想在fun方法执行前后输出一些信息等。
如果采用继承的话,加强ConcreteAComponent,则需要写一个类继承ConcreteAComponent,加强ConcreteBComponent,则需要写一个类继承ConcreteBComponent,就会造成每当要加强一个类时就必须要新建一个类继承它,在代码上造成严重的重复。
除了继承能够进行功能复用外,还有如下的复用方式:
ConcreteTimeDecorator 是一个时间计算装饰器,ConcreteTimeDecorator 实现了Component接口主要是为了替代要装饰的Component 对象。它内部保留了一个Component 的引用,对于那些ConcreteTimeDecorator 并不关心的方法,有具体的Component 对象来实现,而对于想要增强的方法加上自己的逻辑,由于ConcreteTimeDecorator 针对的是接口Component ,不依赖于任何一个具体的Component ,所以每当要增强一个具体的Component时,不用再添加新的类,和继承就不一样了,这样更加容易扩展。
再如下一个装饰着:
也是同样的道理。
我们使用装饰者模式:
运行效果如下:
可见ConcreteTimeDecorator 、ConcretePrintDecorator 对ConcreteAComponent 进行装饰后,加强了对应的功能,同样他们可以对ConcreteBComponent进行装饰加强ConcreteBComponent的功能。整个类图就如下:
这里稍加改动了一些,把ConcreteTimeDecorator和ConcretePrintDecorator的一些共性部分拿出来,作为基类。
这就是装饰者模式,jdk中装饰者模式也很常见,如常用的BufferedInputStream,它就是对InputStream加入了缓冲功能来提高性能,如下所示:
其中FilterInputStream就是一个装饰者的基类,它把所有装饰者共性的部分拿出来,即持有一个InputStream引用,如下:
这种形式和刚才上面的形式基本一样,然后BufferedInputStream再继承FilterInputStream 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
interface
Component {
public
void
fun();
}
public
class
ConcreteAComponent
implements
Component{
@Override
public
void
fun() {
System.out.println(
"ConcreteAComponent"
);
}
}
public
class
ConcreteBComponent
implements
Component{
@Override
public
void
fun() {
System.out.println(
"ConcreteBComponent"
);
}
}
|
接口Component有一个fun()方法,ConcreteAComponent、ConcreteBComponent都实现了该接口,完成了fun方法。现在的需求是,想对ConcreteAComponent、ConcreteBComponent所实现的fun方法进行加强,如想计算出fun方法所花费时间、想在fun方法执行前后输出一些信息等。
如果采用继承的话,加强ConcreteAComponent,则需要写一个类继承ConcreteAComponent,加强ConcreteBComponent,则需要写一个类继承ConcreteBComponent,就会造成每当要加强一个类时就必须要新建一个类继承它,在代码上造成严重的重复。
除了继承能够进行功能复用外,还有如下的复用方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
class
ConcreteTimeDecorator
implements
Component{
private
Component component;
public
ConcreteTimeDecorator(Component component) {
super
();
this
.component = component;
}
@Override
public
void
fun() {
long
start=System.currentTimeMillis();
System.out.println(
"start at "
+start);
component.fun();
long
end=System.currentTimeMillis();
System.out.println(
"end at "
+end+
",cost "
+(end-start));
}
}
|
ConcreteTimeDecorator 是一个时间计算装饰器,ConcreteTimeDecorator 实现了Component接口主要是为了替代要装饰的Component 对象。它内部保留了一个Component 的引用,对于那些ConcreteTimeDecorator 并不关心的方法,有具体的Component 对象来实现,而对于想要增强的方法加上自己的逻辑,由于ConcreteTimeDecorator 针对的是接口Component ,不依赖于任何一个具体的Component ,所以每当要增强一个具体的Component时,不用再添加新的类,和继承就不一样了,这样更加容易扩展。
再如下一个装饰着:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
ConcretePrintDecorator
implements
Component{
private
Component component;
public
ConcretePrintDecorator(Component component) {
super
();
this
.component = component;
}
@Override
public
void
fun() {
System.out.println(
"before real component run"
);
component.fun();
System.out.println(
"after real component run"
);
}
}
|
也是同样的道理。
我们使用装饰者模式:
1
2
3
4
5
6
7
8
|
ConcreteAComponent concreteAComponent=
new
ConcreteAComponent();
ConcreteTimeDecorator concreteTimeDecorator=
new
ConcreteTimeDecorator(concreteAComponent);
concreteTimeDecorator.fun();
System.out.println(
"--------------------------------------------"
);
ConcretePrintDecorator concretePrintDecorator=
new
ConcretePrintDecorator(concreteAComponent);
concretePrintDecorator.fun();
|
运行效果如下:
1
2
3
4
5
6
7
|
start at
1416349131419
ConcreteAComponent
end at
1416349131419
,cost
0
--------------------------------------------
before real component run
ConcreteAComponent
after real component run
|
可见ConcreteTimeDecorator 、ConcretePrintDecorator 对ConcreteAComponent 进行装饰后,加强了对应的功能,同样他们可以对ConcreteBComponent进行装饰加强ConcreteBComponent的功能。整个类图就如下:
这里稍加改动了一些,把ConcreteTimeDecorator和ConcretePrintDecorator的一些共性部分拿出来,作为基类。
这就是装饰者模式,jdk中装饰者模式也很常见,如常用的BufferedInputStream,它就是对InputStream加入了缓冲功能来提高性能,如下所示:
其中FilterInputStream就是一个装饰者的基类,它把所有装饰者共性的部分拿出来,即持有一个InputStream引用,如下:
1
2
3
4
5
6
7
8
9
10
|
public
class
FilterInputStream
extends
InputStream {
protected
volatile
InputStream in;
protected
FilterInputStream(InputStream in) {
this
.in = in;
}
//略
}
|
这种形式和刚才上面的形式基本一样,然后BufferedInputStream再继承FilterInputStream 。