装饰器模式
Contents
模式简介
装饰器模式(Decorator Pattern):在不改变现有对象结构的情况下,动态地给对象增加一些额外的职责,即给现有对象增加一些新的功能。装饰器对客户是透明的,要让客户感受不到该对象被装饰过。因此,装饰器必须要实现被装饰对象的接口方法,从而保证对象的用法不变,不然对象的结构就被改变了。装饰器模式别名又称包装器(Wrapper),与适配器模式别名相同,它属于对象结构型模式。
模式结构
装饰器模式包含4个角色:
1、抽象构件(Component):定义一个抽象接口制定被装饰对象的规范。
2、具体构件(Concrete Component):实现抽象构件的抽象接口,是被装饰的直接对象。
3、抽象装饰器(Decorator):继承自抽象构件接口,并关联抽象构件对象,通过其子类装饰具体构件。
4、具体装饰器(Concrete Decorator):实现抽象装饰器方法,并对具体构件进行装饰,即为具体构件对象添加一些职责。
示例类图
下面以武器中的枪为例,分别通过具体的装饰器把枪装饰为AK47和M4A1。首先分析示例中的模式角色,武器(Weapon)视为抽象构件接口,枪(Gun)视为具体构件类。而AK47和M4A1分别由AK47Decorator类和M4A1Decorator类装饰而来,最后再从两个装饰器中抽象出一个抽象装饰器Decorator类。模式角色分析完毕,该示例的UML类图如下:
示例代码
1、定义抽象构件武器接口,制定被装饰对象的规范。
|
|
2、定义具体构件枪类,实现武器接口,枪类对象为被装饰对象。
|
|
3、定义抽象装饰器类,继承自抽象构件武器接口,并给具体装饰器留下装饰接口。
|
|
4、定义具体装饰器AK47Decorator类,继承自抽象装饰器类,并重写抽象装饰器中的虚方法。
|
|
5、定义具体装饰器M4A1Decorator类,继承自抽象装饰器类,并重写抽象装饰器中的虚方法。
|
|
6、定义一个客户端Client类使用该装饰器。
|
|
7、输出结果:
|
|
应用场景
装饰器模式主要用于,当需要给一个现有类添加额外职责时,而又不能采用继承生成子类的方式的情况。例如,该类被密封(sealed)或是终极类(final),或者通过继承的方式会生成大量子类,使系统变得更复杂。
此外,如果需要将现有的一些功能进行排列组合产生非常多的功能,使用继承会很麻烦。而使用装饰器通过关联的方式很容易实现。由于这种添加额外的功能方式是动态的,因此装饰器模式还可用于动态地为对象添加功能。游戏中经常有遇到各种对象,然后经过装饰器装饰后就增加了额外的属性和方法。
模式总结
模式优点
装饰器模式通过关联的方式动态地为现有对象添加了额外职责(功能),比继承方式更加灵活,类之间的耦合度也降低了。这充分体现了组合/聚合复用原则中“尽量使用关联而不是继承”的理念。通过继承为对象添加功能的方式是静态的,不能控制为对象添加功能的方式和时机,类之间耦合也更深。此外,新建一个具体装饰器十分方便,多个装饰器可以装饰出不同的对象,符合开闭原则。
模式缺点
过多使用装饰器模式会在系统中创建出很多小对象,增大了系统的复杂度。此外,由于装饰器模式比继承方式更灵活也更容易出错,如果装饰层级过多,一旦发生错误,排查错误就是一件很麻烦的事。
模式比较
装饰器模式和适配器模式很相似,甚至别名也相同。但二者的侧重点不同,适配器模式是将已有类的接口转换成另一个类能使用的接口,侧重于互不兼容的两个接口之间的转换逻辑。而装饰器模式是给已有对象动态地添加新功能,不会改变或已有对象的内部接口方法,侧重于添加新的功能。