装饰模式就意图来讲是动态的给主体类增加功能,而这种功能的扩展比单独的使用子类来扩展灵活度更强。那么利用装饰模式比使用子类继承的灵活性在哪呢?
我们知道继承的重要作用之一便是可以对父类的既有的功能进行继承和扩展。但是如果对类A的功能采用继承方式进行扩展,那么这种扩展一旦写好就会在编译时固定下来,在运行期间就只会呈现出这一种功能特征。再有假如我们要给A扩展两种功能,且这两种功能对A的扩展顺序不同会产生不同的扩展结果(例如先对A扩展功能1,再扩展功能2,则产生结果B,要是先扩展功能2,再扩展功能1,则产生结果C),那么用继承来对A进行扩展就必须得使用两个子类来继承A(一个是先扩展功能1,再扩展功能2,另一个相反)才能得到所有扩展结果(如果是三个功能的话,我们就得使用6个子类(或6种排列顺序)来扩展才能得到每一种扩展后的结果)。这就使得要对编译好的类A进行改动十分的不灵活,工作量大!这种扩展功能的方式可以说是静态的,而装饰模式改变这一灵活性差的缺陷的关键点就是它动态的给主体类扩展功能。
我们可以看一下首段链接的装饰模式的结构图,Decorator类继承类又Component类,而Component聚合成了Decorator类,我的相册 -》UML中类间的五种关系中说过他们分别是is a和has a的关系。这个is a和has a同时发生确实有些蹊跷,不过我们在代码实现时马上就会发现,这个has a,并非是Decorator类中包含一个Component类,而是定义了这么一种类似于接口作用的抽象类型,方便我们在Decorator类中动态实例化继承于Component类的实体类(如ConcreteComponent子类等)以达到装饰实体类的目的。这一点可以动态的选择继承于Component类的子类进行装饰,那么与之前说的继承方式实现的静态扩展相比的动态表现在哪呢?
我们要对A扩展1、2、3三个功能,有六种不同的扩展顺序,用继承的话就得将这六种继承顺序在编译前写好,而采用装饰模式则只需将那三个必备的功能继承于Decorator类,根据需要的装饰结果在客户端动态的产生这三个具体的装饰类,并按此结果所需的装饰顺序将这三个具体装饰类排列传参即可。
现在讲完了第一点解释:动态的给主体类增加功能,而这种功能的扩展比单独的使用子类来扩展灵活度更强。
在第二段中我在用子类继承来扩展A类的功能时,如果一次又一次的扩展,那就会形成庞大的子类系统,造成子类衍生问题。在用装饰模式来扩展功能时各个功能子类并不是纵向扩展的而是横向扩展的,这就很好的解决了子类衍生问题。但在此要注意装饰模式虽然能够解决子类衍生问题,但装饰模式的工作重点不在于此,而在于我讲的第一点,并且不是所有的子类衍生问题都可以用此模式来解决(即有其他的模式来解决子类衍生的问题)
这两点内容总的来讲就是Decorator模式并非解决子类衍生问题,它应用的要点应该在主体类多方向扩展功能的问题上。
其代码简单实现如下: