设计模式学习笔记--Decorator装饰模式
Decorator装饰模式:主要用于动态地给一个对象添加一些额外的职责。就扩展功能而言,它比生成子类方式更为灵活。
先进入我们的例子:
程序如下图
定义抽象基类 AbsCar,此处它代表一个抽象的“车”,它既是装饰类的基类,也是被装饰类的基类,其代码如下
定义Decorator类,此类继承自AbsCar类,同时又是具体装饰类的基类,此处它代表“装饰”概念,但还没有进一步实例化为具体的“装饰”内容,代码如下:
定义具体的装饰类DecoratorCruiseCtrl,DecoratorGPSCtrl两个类,它们继承自Decorator类,代表具体的“装饰”内容,此处就是Cruise巡航功能和GPS全球定位功能,它们的代码如下:
定义具体的被装饰对象"丰田车":ToyotaCar,当然你还可以定义其它的被装饰对象如宝马车,奔驰车.........代码如下:
应用程序代码:
示例说明:
由上面的程式可以了解,未來要添加一个新的功能,例如:想加一个天窗SunRoof,只要寫一個和DecoratorCruiseCtrl以及DecoratorGPSCtrl功能一樣的class繼承Decorator。这个個模式最有趣的是,Decorator既繼承了AbsCar,也合成AbsCar, 也就是说 Decorator 是装饰者模式里非常特殊的一个类,它既继承于 AbsCar【IS A关系】,又维护一个指向 AbsCar实例的引用【HAS A关系】,换个角度来说,Decorator 跟 AbsCar之间,既有动态组合关系,又有静态继承关系。
1、为什么要这样设计?我们知道,组合的好处是可以在运行时给对象增加职责,Decorator【HAS A】AbsCar的目的,是让 Decorator可以在运行时动态地给 AbsCar增加职责,这一点相对来说还比较好理解;
2、Decorator继承于 AbsCar的目的是什么?目的只有一个,那就是统一「装饰者」(DecoratorCruiseCtrl,DecoratorGPSCtrl或者其它任何想加的具体Decorator)和「被装饰者」(丰田车或者其它任何品牌的车)的接口。换个角度来说,不管是什么被装饰者(丰田车)还是「装饰者」(DecoratorCruiseCtrl,DecoratorGPSCtrl),它们都继承自最顶层的 AbsCar 基类,用户代码可以把它们统一看作 AbsCar来处理,这样带来的更深一层好处就是,「装饰者」对象(DecoratorCruiseCtrl,DecoratorGPSCtrl),对「被装饰者」对象(丰田车)的功能职责扩展,对用户代码来说是完全透明的,因为用户代码引用的都是 AbsCar,所以就不会因为「被装饰者」(丰田车)对象在被装饰后,引用它的用户代码发生错误,实际上不会有任何影响,因为装饰前后,用户代码引用的都是 AbsCar 类型的对象。
因此「装饰模式」通过继承,实现统一了「装饰者」和「被装饰者」的接口,通过组合获得了在运行时动态扩展「被装饰者」对象的能力。
程序运行效果:
总结:
Decorator Pattern 适用的情景:
你拥有一个已存在的组件类,却无法继承它 (subclassing)。
能够动态地为对象添加职责 (添加状态和行为)。
改变类中的成员和行为,但不影响其他对象。
希望能便于职责的撤消。
不想用「继承」来扩展行为。其中一种原因是避免当一些功能要交叉搭配引用时,单独用「继承」来设计会产生太多的子类、太复杂的类图结构,另一种考量可能是因为类的定义被隐藏,或类的定义不能用于生成子类。
Decorator Pattern 的优点:
可避免单独使用「继承」时,在扩展时不够弹性,且可能衍生过多的子类。
扩展时不需要修改既有的代码。
可在执行时期,动态地添加新行为 (职责)。
Decorator Pattern 的缺点:
可能会在程序中出现许多的小型类,亦即需要编写很多 ConcreteDecorator 类 (具体装饰者)。
若过度使用 Decorator 模式,会让程序逻辑变得很复杂。
别人较不易理解设计方式及代码,排查故障、追踪和调试也比较困难。
Decorator Pattern 的其他特性:
每个要装饰的功能,都放在单独的类中。
我们可以用无数个装饰者,去包装一个组件。
「装饰者」可以在「被装饰者」前面或后面,添加自己的行为,甚至将「被装饰者」的行为整个取代掉,以达到特定的目的。
「被装饰者」并不需要知道它已经被「装饰」过了,亦即 Component 类 (对象) 并不需要知道 Decorator 类 (对象) 的存在,且 Decorator 也仅仅认识 Component。