研磨设计模式之装饰模式-2
2? 解决方案2.1? 装饰模式来解决
??????? 用来解决上述问题的一个合理的解决方案,就是使用装饰模式。那么什么是装饰模式呢?
(1)装饰模式定义
?(2)应用装饰模式来解决的思路
??????? 虽然经过简化,业务简单了很多,但是需要解决的问题不会少,还是要解决:要透明的给一个对象增加功能,并实现功能的动态组合。
??????? 所谓透明的给一个对象增加功能,换句话说就是要给一个对象增加功能,但是不能让这个对象知道,也就是不能去改动这个对象。而实现了能够给一个对象透明的增加功能,自然就能够实现功能的动态组合,比如原来的对象有A功能,现在透明的给它增加了一个B功能,是不是就相当于动态组合了A和B功能呢。
??????? 要想实现透明的给一个对象增加功能,也就是要扩展对象的功能了,使用继承啊,有人马上提出了一个方案,但很快就被否决了,那要减少或者修改功能呢?事实上继承是非常不灵活的复用方式。那就用“对象组合”嘛,又有人提出新的方案来了,这个方案得到了大家的赞同。
??????? 在装饰模式的实现中,为了能够和原来使用被装饰对象的代码实现无缝结合,是通过定义一个抽象类,让这个类实现与被装饰对象相同的接口,然后在具体实现类里面,转调被装饰的对象,在转调的前后添加新的功能,这就实现了给被装饰对象增加功能,这个思路跟“对象组合”非常类似。如果对“对象组合”不熟悉,请参见3.1的第2小节。
在转调的时候,如果觉得被装饰的对象的功能不再需要了,还可以直接替换掉,也就是不再转调,而是在装饰对象里面完全全新的实现。
2.2? 模式结构和说明
?装饰模式的结构如图1所示:
?
??????????????????????????????????????????????? 图1? 装饰模式结构图
Component:
????????组件对象的接口,可以给这些对象动态的添加职责。
ConcreteComponent:
????????具体的组件对象,实现组件对象接口,通常就是被装饰器装饰的原始对象,也就是可以给这个对象添加职责。
Decorator:
??????? 所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象,其实就是持有一个被装饰的对象。
??????? 注意这个被装饰的对象不一定是最原始的那个对象了,也可能是被其它装饰器装饰过后的对象,反正都是实现的同一个接口,也就是同一类型。
ConcreteDecorator:
??????? 实际的装饰器对象,实现具体要向被装饰对象添加的功能。
2.3? 装饰模式示例代码
(1)先来看看组件对象的接口定义,示例代码如下:
????????????????????????? ?图2? 使用装饰模式重写示例的程序结构示意图
(1)计算奖金的组件接口和基本的实现对象
??????? 在计算奖金的组件接口中,需要定义原本的业务方法,也就是实现奖金计算的方法,示例代码如下:
??????????????????????????????? 图3? 装饰模式示例的组合和调用过程示意图
??????? 这个图很好的揭示了装饰模式的组合和调用过程,请仔细体会一下。
?
?????????如同上面的示例,对于基本的计算奖金的对象而言,由于计算奖金的逻辑太过于复杂,而且需要在不同的情况下进行不同的运算,为了灵活性,把多种计算奖金的方式分散到不同的装饰器对象里面,采用动态组合的方式,来给基本的计算奖金的对象增添计算奖金的功能,每个装饰器相当于计算奖金的一个部分。
???????这种方式明显比为基本的计算奖金的对象增加子类来得更灵活,因为装饰模式的起源点是采用对象组合的方式,然后在组合的时候顺便增加些功能。为了达到一层一层组装的效果,装饰模式还要求装饰器要实现与被装饰对象相同的业务接口,这样才能以同一种方式依次组合下去。
?????? 灵活性还体现在动态上,如果是继承的方式,那么所有的类实例都有这个功能了,而采用装饰模式,可以动态的为某几个对象实例添加功能,而不是对整个类添加功能。比如上面示例中,客户端测试的时候,对张三李四就只是组合了两个功能,对王五就组合了三个功能,但是原始的计算奖金的类都是一样的,只是动态的为它增加的功能不同而已。
?
?
2? 解决方案2.1? 装饰模式来解决
??????? 用来解决上述问题的一个合理的解决方案,就是使用装饰模式。那么什么是装饰模式呢?
(1)装饰模式定义
?(2)应用装饰模式来解决的思路
??????? 虽然经过简化,业务简单了很多,但是需要解决的问题不会少,还是要解决:要透明的给一个对象增加功能,并实现功能的动态组合。
??????? 所谓透明的给一个对象增加功能,换句话说就是要给一个对象增加功能,但是不能让这个对象知道,也就是不能去改动这个对象。而实现了能够给一个对象透明的增加功能,自然就能够实现功能的动态组合,比如原来的对象有A功能,现在透明的给它增加了一个B功能,是不是就相当于动态组合了A和B功能呢。
??????? 要想实现透明的给一个对象增加功能,也就是要扩展对象的功能了,使用继承啊,有人马上提出了一个方案,但很快就被否决了,那要减少或者修改功能呢?事实上继承是非常不灵活的复用方式。那就用“对象组合”嘛,又有人提出新的方案来了,这个方案得到了大家的赞同。
??????? 在装饰模式的实现中,为了能够和原来使用被装饰对象的代码实现无缝结合,是通过定义一个抽象类,让这个类实现与被装饰对象相同的接口,然后在具体实现类里面,转调被装饰的对象,在转调的前后添加新的功能,这就实现了给被装饰对象增加功能,这个思路跟“对象组合”非常类似。如果对“对象组合”不熟悉,请参见3.1的第2小节。
在转调的时候,如果觉得被装饰的对象的功能不再需要了,还可以直接替换掉,也就是不再转调,而是在装饰对象里面完全全新的实现。
2.2? 模式结构和说明
?装饰模式的结构如图1所示:
?
??????????????????????????????????????????????? 图1? 装饰模式结构图
Component:
????????组件对象的接口,可以给这些对象动态的添加职责。
ConcreteComponent:
????????具体的组件对象,实现组件对象接口,通常就是被装饰器装饰的原始对象,也就是可以给这个对象添加职责。
Decorator:
??????? 所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象,其实就是持有一个被装饰的对象。
??????? 注意这个被装饰的对象不一定是最原始的那个对象了,也可能是被其它装饰器装饰过后的对象,反正都是实现的同一个接口,也就是同一类型。
ConcreteDecorator:
??????? 实际的装饰器对象,实现具体要向被装饰对象添加的功能。
2.3? 装饰模式示例代码
(1)先来看看组件对象的接口定义,示例代码如下:
????????????????????????? ?图2? 使用装饰模式重写示例的程序结构示意图
(1)计算奖金的组件接口和基本的实现对象
??????? 在计算奖金的组件接口中,需要定义原本的业务方法,也就是实现奖金计算的方法,示例代码如下:
??????????????????????????????? 图3? 装饰模式示例的组合和调用过程示意图
??????? 这个图很好的揭示了装饰模式的组合和调用过程,请仔细体会一下。
?
?????????如同上面的示例,对于基本的计算奖金的对象而言,由于计算奖金的逻辑太过于复杂,而且需要在不同的情况下进行不同的运算,为了灵活性,把多种计算奖金的方式分散到不同的装饰器对象里面,采用动态组合的方式,来给基本的计算奖金的对象增添计算奖金的功能,每个装饰器相当于计算奖金的一个部分。
???????这种方式明显比为基本的计算奖金的对象增加子类来得更灵活,因为装饰模式的起源点是采用对象组合的方式,然后在组合的时候顺便增加些功能。为了达到一层一层组装的效果,装饰模式还要求装饰器要实现与被装饰对象相同的业务接口,这样才能以同一种方式依次组合下去。
?????? 灵活性还体现在动态上,如果是继承的方式,那么所有的类实例都有这个功能了,而采用装饰模式,可以动态的为某几个对象实例添加功能,而不是对整个类添加功能。比如上面示例中,客户端测试的时候,对张三李四就只是组合了两个功能,对王五就组合了三个功能,但是原始的计算奖金的类都是一样的,只是动态的为它增加的功能不同而已。
?
注:本文转自???http://chjavach.iteye.com