装饰模式
装饰模式:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。【DP】
图1 装饰模式类图
Component是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator是装饰抽象类,继承Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。【DPE】
可以通过在构造ConcreteDecorator对象或调用setComponent类似的函数来传入对ConcreteComponent具体对象的引用,以此来对ConcreteComponent具体对象进行封装。每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中【DPE】。
笔者见过的关于装饰模式的解说举例大多都是应用在程序外观方面,因此就存在一个“对象链”,这种实现是将ConcreteDecorator这些具体的装饰对象“串联”起来,它们都同时作用于ConcreteComponent具体对象。但其实还有另外一种应用,可将ConcreteDecorator这些具体的装饰对象“并联”起来,只在需要某个功能时才调用具体的装饰来作用于ConcreteComponent具体对象,这种模式可能应用到逻辑处理方面比较合适。
对于一些观点认为,如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类(如图2所示)。笔者并不认同该观点,正如Scott Meyers所言,对于继承,子类与父类的关系必须满足"is-a"的关系,而"Decorator is a ConcreteComponent"的关系很大程度上是不成立的。所以笔者认为Component抽象类的存在还是很必要的(如图3所示)。然而,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,可以把Decorator和ConcreteDecorator的责任合并成一个类。
图2 人着装类图1
图3 人着装类图2
总之,装饰模式是为已有功能动态地添加更多功能的 一种方式。其优点是把类中的装饰功能从类中搬移去除,这样可以简化原有的类,有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑(“串联”时)。装饰模式也有其缺点,在进行系统设计上往往会产生许多看上去类似的小对象,使得这个系统难以被理解,排错难度也增加。
对于装饰模式的一些优缺点及其注意事项建议参考《设计模式》(P117)一书。