对于装饰模式我们先看官方的介绍
在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。由于java的封装继承多态三个特性使得我们充分扩展父类的功能,装饰者模式就是建立在这样的基础上的。设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。为了更好的说明装饰模式的使用,下面引用下面博主的举例,相关链接
http://blog.csdn.net/jason0539/article/details/22713711
实际上Java 的I/O API就是使用Decorator实现的。
[java] view plain copy
运行结果:
我们现在来看看装饰者模式的 uml 类图:
装饰者模式共有四大角色:
可以是一个接口或者是抽象类,其充当的就是被装饰的原始对象,用来定义装饰者和被装饰者的基本行为。
该类是 Component 类的基本实现,也是我们装饰的具体对象。
装饰组件对象,其内部一定要有一个指向组件对象的引用。在大多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类。当然,如果是装饰逻辑单一,只有一个的情况下我们可以忽略该类直接作为具体的装饰者。
对抽象装饰者的具体实现。
在已有的 Component 和 ConcreteComponent 体系下,实现装饰者模式来扩展原有系统的功能,可以分为 5 个步骤
装饰者模式在源码中用的也是非常多的,在 Java 和 Android 中都能够见到装饰者模式的影子:
最典型的就是 Java 中的 java.io 包下面的 InputStream 和 OutputStream 相关类了,初学 Java 的时候,看到这些类,头都大了,其实学了装饰者模式之后,再理解这些类就很简单了,画一个简单的类图来表示:
InputStream 类是一个抽象组件, FileInputStream,StringBufferInputStream 和 ByteArrayInputStream 类都是可以被装饰者包起来的具体组件;FilterInputStream 是一个抽象装饰者,所以它的四个子类都是一个个装饰者了。
其次,对于 android 开发工程师来说,最最重要的就应该是“上帝类” Context 和其子类了,这些类我就不用解释了,上一张类图基本就明确了:
所以对于 Application,Activity 和 Service 等类来说,他们只是一个个装饰者,都是用来装饰 ContextImpl 这个被装饰者类,Application 是在 createBaseContextForActivity 方法中,通过 ContextImpl 的静态方法 createActivityContext 获得一个 ContextImpl 的实例对象,并通过 setOuterContext 方法将两者建立关联;Activity 是通过 handleLaunchActivity 方法设置的 ContextImpl 实例,这个方法会获取到一个Activity对象,在performLaunchActivity函数中会调用该activity的attach方法,这个方法把一个ContextImpl对象attach到了Activity中,具体可以看看我的这篇博客,里面详细介绍到了 Activity 的启动过程:android 不能在子线程中更新ui的讨论和分析。别的类在这里就不介绍了,具体的大家可以去网上查阅相关资料。
我们这里以一个图形系统中的 Window 为例,一般情况窗口都是能够垂直或者是左右欢动的,所以为了能够更好的支持 Window 的滑动,给滑动的 Window 加上一个 ScrollBar 是一个不错的方法,为了重用代码,水平滑动的 Window 和垂直滑动的 Window 我们就能够使用装饰者模式去处理,基本类图如下所示:
根据类图,我们首先实现 Window 这个接口:
IWindow.class
1
2
3
4
5
6
|
public
interface
IWindow {
void
draw();
String getDescription();
}
|
然后是被装饰者 SimpleWindow 类,它实现了窗口的基本行为:
SimpleWindow.class
1
2
3
4
5
6
7
8
9
10
11
|
public
class
SimpleWindow
implements
IWindow {
@Override
public
void
draw() {
Log.e(
"shawn"
,
"drawing a window"
);
}
@Override
public
String getDescription() {
return
"a window"
;
}
}
|
然后是装饰者类角色的抽象父类:
WindowDecorator.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
abstract
class
WindowDecorator
implements
IWindow{
private
IWindow window;
public
WindowDecorator(IWindow window) {
this
.window = window;
}
@Override
public
void
draw() {
window.draw();
}
@Override
public
String getDescription() {
return
window.getDescription();
}
}
|
最后是实现该装饰者父类的装饰者子类:
HorizontalScrollBarDecorator.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
HorizontalScrollBarDecorator
extends
WindowDecorator {
public
HorizontalScrollBarDecorator(IWindow window) {
super
(window);
}
@Override
public
void
draw() {
super
.draw();
Log.e(
"shawn"
,
"then drawing the horizontal scroll bar"
);
}
@Override
public
String getDescription() {
return
super
.getDescription() +
" with horizontal scroll bar"
;
}
}
|
VerticalScrollBarDecorator.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
VerticalScrollBarDecorator
extends
WindowDecorator {
public
VerticalScrollBarDecorator(IWindow window) {
super
(window);
}
@Override
public
void
draw() {
super
.draw();
Log.e(
"shawn"
,
"then drawing the vertical scroll bar"
);
}
@Override
public
String getDescription() {
return
super
.getDescription() +
" with vertical scroll bar"
;
}
}
|
最后测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
|
switch
(v.getId()) {
case
R.id.btn_horizontal_window:
IWindow horizontalWindow =
new
HorizontalScrollBarDecorator(
new
SimpleWindow());
horizontalWindow.draw();
Log.e(
"shawn"
,
"window description : "
+ horizontalWindow.getDescription());
break
;
case
R.id.btn_vertical_window:
IWindow verticalWindow =
new
VerticalScrollBarDecorator(
new
SimpleWindow());
verticalWindow.draw();
Log.e(
"shawn"
,
"window description : "
+ verticalWindow.getDescription());
break
;
}
|
结果:
1
2
3
4
5
6
|
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the horizontal scroll bar
com.android.decoratorpattern E/shawn: window description : a window with horizontal scroll bar
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the vertical scroll bar
com.android.decoratorpattern E/shawn: window description : a window with vertical scroll bar
|
代码一目了然,结构清晰。
其实说到底,每一个写过 Android 程序的人都应该用过装饰者模式,因为每写一个 Activity,就相当于是写了一个装饰者类,不经意间就用了装饰者模式,大家想一想是不是,哈哈~~