1.装饰模式的概述
2.1 什么是装饰模式
在不改变对象的前提下,动态增加其功能,即我们不希望改变原有的类,或采用创建子类的方法增加功能,这种情况下需要采用装饰模式。
2.2结构
修饰一个对象后,其接口不应该发生变化;否则这个对象不能被原有调用者使用,修饰失去了意义。由此引出了装饰模式结构最重要的一点,即装饰者和被装饰者具有相同的接口。换句话说,动态增加的功能不应该破坏已有的接口。
装饰模式的结构如下图所示。
装饰模式的结构图
(1)Component:定义一个对象接口,可以动态添加这些对象的功能。
(2)ConcreteComponent:定义一个对象,可以为其添加一些功能。
(3)Decorator:维持一个对Component对象的引用,并定义与Component接口一致的接口。
(4)ConcreteDecorator:为组件添加功能。
2.3 什么情况下是用装饰模式
以下情况使用装饰模式。
(1)在不影响其他对象的情况下,以动态且透明的方式添加单个对象的功能。
(2)处理那些可以撤销的功能。
(3)不能采用生成子类的方法扩充时。
2.4实现时的注意事项
实现时的注意事项如下。
(1)接口的一致性:装饰模式中被装饰对象对用户而言是透明的,用户仍然可以直接访问被装饰对象,并且装饰后的对象在访问时不就变化。如果接口不一致,尽管也达到了为对象增加功能的目的,但并不是装饰模式。
(2)保持被装饰类的简单性:被装饰类需要功能单一,这样才能使结构更灵活。比如显示最新新闻的组件,由标题和主体组成。
其中的核心组件应该显示若干条最近的新闻,我们可以用一个组件显示新闻,加一个显示标题和样式。解决问题的方法是核心组件保持最小的功能,显示新闻标题,每个装饰器也只完成一项功能。我们可以增加一个显示more按钮的装饰器,使得装饰器可以通过组合完成更多的功能。
2.5效果
使用装饰模式的优点是比静态继承灵活,并可避免在层次结构高层的类有太多的特征;缺点是产生许多小对象。
2.用一个实例来解说装饰模式
做BS的朋友们都会遇到网页组件装饰器的实现问题,我们希望为用户自定义组件创建可以通用的装饰器。为此需要定义一个装饰器的基类,代码如下:
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
在具体的装饰者中,后台的可执行代码很少,主要定义装饰界面,在SubDecorator中定义了带有图形边框的界面:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在另一个装饰器中如下定义了可以使被装饰者滚动显示的SubDecoratorB.
我们定义一个很简单的HelloWorld用户组件用来测试,这个组件没有后台代码,仅仅有一个Lable组件:
<asp:Label Runat="server" >