Design Patterns Talk - Decorator

2017-04-01  本文已影响0人  su3

《大话设计模式》第 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 

总结

装饰模式是为已有功能动态添加更多功能的一种方式。把每个装饰功能放在单独的类中,并用这个类包装它所要装饰的对象。客户代码可以根据需要有选择地使用装饰功能来依次包装对象,可以以随意的顺序组合装饰。

这样有效地把类的核心功能和装饰功能区分开。要增加装饰时不需要改动任何已有代码。

playground

上一篇下一篇

猜你喜欢

热点阅读