定义
Decorator Pattern
在不改变接口的情况下,动态的扩展一个对象的功能。通过包装对象来实现,又称为wrapper模式。
装饰者模式采用组合的方式,依赖于抽象,能够动态的扩展功能。
涉及到的角色有:
Component:定义了一个接口,包含所需要的功能
ConcreteComponent:具体的组件
Decorator:装饰者,持有Component的实例,与Component有一样的接口。
ConcreteDecorator:具体的装饰者。负责给对象扩展功能。
UML图
- 装饰者和被装饰者有着相同的类型
- 可以用多个装饰者装饰一个对象
- 装饰者可以在被装饰者原有行为之前或之后,添加自己的行为。
- 被装饰对象可以被装饰对象所代替。
实现例子
还是拿Head First上的例子。
一个咖啡馆里有深焙咖啡,脱因咖啡等,可以加摩卡、奶泡、牛奶等等其他的调料,需要计算出各种种类的价钱。比如深焙咖啡+摩卡,脱因咖啡+摩卡+奶泡,xx咖啡+其他调料等等。
其实这里咖啡就是被装饰者,其他的调料就是装饰者。
代码如下:github地址
protocol Component {
func getDescription() -> String
func cost() -> Double
}
// 具体被装饰者,深焙咖啡
class DarkRoast: Component {
func getDescription() -> String {
return "DarkRoast"
}
func cost() -> Double {
return 10.0
}
}
// 脱因咖啡
class Decaf: Component {
func getDescription() -> String {
return "Decaf"
}
func cost() -> Double {
return 20.0
}
}
// 装饰者基类
class Decorator: Component {
var obj: Component
init(obj: Component) {
self.obj = obj
}
func getDescription() -> String {
return obj.getDescription()
}
func cost() -> Double {
return obj.cost()
}
}
// 牛奶
class Milk: Decorator {
override func getDescription() -> String {
return self.obj.getDescription() + " Milk"
}
override func cost() -> Double {
return 2.0 + self.obj.cost()
}
}
// 摩卡
class Mocha: Decorator {
override func getDescription() -> String {
return self.obj.getDescription() + " Mocha"
}
override func cost() -> Double {
return 3.0 + self.obj.cost()
}
}
// 奶泡
class Whip: Decorator {
override func getDescription() -> String {
return self.obj.getDescription() + " Whip"
}
override func cost() -> Double {
return 4.0 + self.obj.cost()
}
}
调用:
// 现在我需要一杯深焙咖啡+摩卡
var darkRoast: Component = DarkRoast()
darkRoast = Mocha(obj: darkRoast)
print("深焙咖啡+摩卡,\(darkRoast.getDescription()),cost:\(darkRoast.cost())")
// output:深焙咖啡+摩卡,DarkRoast Mocha,cost:13.0
// 脱因咖啡+奶泡+牛奶,可被多个装饰者装饰。
var decaf: Component = Decaf()
decaf = Whip(obj: decaf)
decaf = Milk(obj: decaf)
print("脱因咖啡+奶泡+牛奶,\(decaf.getDescription()),cost:\(decaf.cost())")
// output:脱因咖啡+奶泡+牛奶,Decaf Whip Milk,cost:26.0
// 深焙咖啡+双倍摩卡+牛奶
var darkRoast1: Component = DarkRoast()
darkRoast1 = Mocha(obj: darkRoast1)
darkRoast1 = Mocha(obj: darkRoast1)
darkRoast1 = Milk(obj: darkRoast1)
print("深焙咖啡+双倍摩卡+牛奶,\(darkRoast1.getDescription()),cost:\(darkRoast1.cost())")
//output:深焙咖啡+双倍摩卡+牛奶,DarkRoast Mocha Mocha Milk,cost:18.0