0%

装饰者模式入门

基本概念

装饰者模式通过创建一个装饰对象来包裹真实的对象,动态地将责任附加到对象上。若要扩展功能,装饰着提供了比继承更有弹性的替代方案。

以下情况推荐使用装饰者模式:

  1. 需要扩展一个类的功能,或给一个类添加附加职责。
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

装饰者模式的优点:

  1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
  2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

装饰者模式的缺点:

  1. 比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
  2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
  3. 装饰模式是针对抽象组件(Component)类型编程。如果要针对具体组件编程时,就应该重新思考应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

UML类图

说明:

  1. 装饰者和被装饰对象具有相同的超类型,在任何需要原始对象(被装饰者)的场合,都可以用装饰过的对象代替。
  2. 可以用一个或多个装饰者包装一个对象。
  3. 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定目的。

代码示例

装饰者模式最典型的例子莫过于<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