《大话设计模式》第 6 章 - 装饰模式 的 Swift 实现。
问题
对一个人进行装扮,衣服、鞋子、领带等等,考虑不同的人有不同装扮,并且便于增加装扮。
方案
把装饰功能按特性的不同拆分到各自单独的子类中,交给交互端根据需要进行组合搭配,每个装饰类传入上一个装饰完成之后的对象,这样就能把用户选择的装饰串联起来,完成最终的装饰,同时装饰类随时可以添加,不影响已有的装饰。
1. Component,定义一个接口协议,抽象化装饰组件
protocol Person{
func show()
}
2. ConcreteComponent 类,定义具体的对象,也可以给这个对象添加一些职责
class SimplePerson: Person{
private let name: String
init(name: String){
self.name = name
}
func show(){
print("装扮的 \(name) ")
}
}
3. Decorator,装饰类,遵循 Component 协议。Component 无需知道 Decorator 的存在。
required 关键字要求子类必须传入装饰过的对象。并在装饰方法中执行实例对象的核心方法。
class PersonDecorator: Person{
let decoratedPerson: Person
required init(decorated: Person){
self.decoratedPerson = decorated
}
func show() {
decoratedPerson.show()
}
}
4. ConcreteDecorator,具体的装饰器,实现 component 要的职责。
Decorator 的子类,初始化方法中传入一个已装饰的对象,依次应用装饰类,就可以把用到的装饰组合起来。
final class Tee: PersonDecorator{
required init(decorated: Person) {
super.init(decorated: decorated)
}
override func show() {
print("T恤", separator: "", terminator: " ")
super.show()
}
}
final class BeachShorts: PersonDecorator{
required init(decorated: Person) {
super.init(decorated: decorated)
}
override func show() {
print("沙滩裤", separator: "", terminator: " ")
super.show()
}
}
final class Sunglasses: PersonDecorator{
required init(decorated: Person) {
super.init(decorated: decorated)
}
override func show() {
print("墨镜", separator: "", terminator: " ")
super.show()
}
}
测试
var someone: Person = SimplePerson(name: "Tom") //即将被装饰的对象,可以有一些基础属性
someone = Tee(decorated: someone) //用 Tee 去装饰 someone
someone = BeachShorts(decorated: someone) //在上一步装饰好之后继续装饰
someone = Sunglasses(decorated: someone) //继续用 Sunglasses 去装饰前两步装饰过的对象
someone.show()
输出
墨镜 沙滩裤 T恤 装扮的 Tom
总结
装饰模式是为已有功能动态添加更多功能的一种方式。把每个装饰功能放在单独的类中,并用这个类包装它所要装饰的对象。客户代码可以根据需要有选择地使用装饰功能来依次包装对象,可以以随意的顺序组合装饰。
这样有效地把类的核心功能和装饰功能区分开。要增加装饰时不需要改动任何已有代码。