基本概念
装饰者模式通过创建一个装饰对象来包裹真实的对象,动态地将责任附加到对象上。若要扩展功能,装饰着提供了比继承更有弹性的替代方案。
以下情况推荐使用装饰者模式:
- 需要扩展一个类的功能,或给一个类添加附加职责。
- 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
- 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
装饰者模式的优点:
- Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
- 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
装饰者模式的缺点:
- 比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
- 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
- 装饰模式是针对抽象组件(Component)类型编程。如果要针对具体组件编程时,就应该重新思考应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
UML类图
说明:
- 装饰者和被装饰对象具有相同的超类型,在任何需要原始对象(被装饰者)的场合,都可以用装饰过的对象代替。
- 可以用一个或多个装饰者包装一个对象。
- 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定目的。
代码示例
装饰者模式最典型的例子莫过于<Head First 设计模式>中咖啡店的例子, 具体Swift实现如下:
定义抽象Component:
1 2 3 4 5 6
| //相当于抽象的Component protocol IBeverage { var description: String {get} func cost() -> Double }
|
定义抽象装饰者:
1 2 3 4 5
| //swift示例中无具体实现, 此时装饰者模式可以简化为只有一个IBeverage protocol ICondimentDecorator: IBeverage { }
|
定义ConcreteComponent:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| //具体Beverage class Espresso: IBeverage { var description: String = "Espresso" func cost() -> Double { return 1.99 } }
class HouseBlend: IBeverage { var description: String = "HouseBlend" func cost() -> Double { return 0.89 } }
|
定义ConcreteDecorate:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| //具体调料 class Mocha: ICondimentDecorator { var description: String { return self.beverage.description + ",Mocha" } var beverage: IBeverage func cost() -> Double { return 0.2 + self.beverage.cost() } init(beverage: IBeverage) { self.beverage = beverage } }
class Whip: ICondimentDecorator { var description: String { return self.beverage.description + ",Whip" } var beverage: IBeverage func cost() -> Double { return 0.3 + self.beverage.cost() } init(beverage: IBeverage) { self.beverage = beverage } }
|
客户端调用:
1 2 3 4 5 6 7 8 9
| var beverage: IBeverage = DarkRoast() print(beverage.description + "\t价格: $ \(beverage.cost())")
beverage = Whip(beverage: beverage) print(beverage.description + "\t价格: $ \(beverage.cost())")
beverage = Mocha(beverage:beverage) print(beverage.description + "\t价格: $ \(beverage.cost())")
|
输出:
1 2 3
| DarkRoast 价格: $ 2.99 DarkRoast,Whip 价格: $ 3.29 DarkRoast,Whip,Mocha 价格: $ 3.49
|