设计模式-3.装饰模式

121 阅读3分钟

一句话总结

装饰模式是动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。

需求

为虚拟人物设计皮肤功能,类似QQ秀。

Code V1.0

很容易的创建一个Person类,提供一些穿着能力。但是如果想增加皮肤,得修改Person类。这样就不符合开放-封闭原则了。

static func showDecorator() {
    print("装扮1")
    let ming = Person(name: "小明")
    ming.wearTShirt()
    ming.wearBigTrouser()
    ming.wearSneaker()
    ming.show()
    
    print("")
    print("装扮2")
    ming.wearSuit()
    ming.wearTie()
    ming.wearLeatherShoes()
    ming.show()
}

class Person {
    let name: String
    
    init(name: String) {
        self.name = name
    }
    
    func wearTShirt() {
        print("大T恤")
    }
    
    func wearBigTrouser() {
        print("大垮裤")
    }
    
    func wearSneaker() {
        print("破球鞋")
    }
    
    func wearSuit() {
        print("西装")
    }
    
    func wearTie() {
        print("领带")
    }
    
    func wearLeatherShoes() {
        print("皮鞋")
    }
    
    func show() {
        print("装扮的\(name)")
    }
}

Code V2.0

可以抽出来一个装扮Finery协议,让各种皮肤类都遵守这个协议。这样增加新的皮肤的时候,只需要新增一个遵守Finery协议的皮肤类就行。但是这样还有一个问题,就是在调用皮肤类的时候,相当于把装扮过程暴露给使用方。是不合适的。

static func showDecorator() {
    let ming = Person(name: "小明")
    print("第一种装扮")
    let _ = TShirt().show()
    let _ = BigTrouser().show()
    let _ = Sneaker().show()
    ming.show()
    
    print("")
    print("第二种装扮")
    let _ = Suit().show()
    let _ = Tie().show()
    let _ = LeatherShoes().show()
    ming.show()
}

class Person {
    var name: String = ""
    
    init() { }
    init(name: String) {
        self.name = name
    }
    
    func show() {
        print("装扮的\(name)")
    }
}

protocol Finery {
    func show()
}

class TShirt: Finery {
    func show() {
        print("大T恤")
    }
}

class BigTrouser: Finery {
    func show() {
        print("大垮裤")
    }
}

class Sneaker: Finery {
    func show() {
        print("破球鞋")
    }
}

class Suit: Finery {
    func show() {
        print("西装")
    }
}

class Tie: Finery {
    func show() {
        print("领带")
    }
}

class LeatherShoes: Finery {
    func show() {
        print("皮鞋")
    }
}

装饰模式

先来看一下标准的装饰模式。每个装饰对象和如何使用这个对象分离开了,每个装饰对象(例:ConcreteDecoratorA)只关心自己的功能,不需要关心如何被添加到对象链中。

static func showDecorator() {
    let c = ConcreteComponent()
    let d1 = ConcreteDecoratorA(component: c)
    let d2 = ConcreteDecoratorB(component: d1)
    
    d2.operation()
}

protocol Component {
    func operation()
}

class ConcreteComponent: Component {
    func operation() {
        print("具体对象的操作")
    }
}

class Decorator: Component {
    let component: Component
    
    init(component: Component) {
        self.component = component
    }
    
    func operation() {
        component.operation()
    }
}

class ConcreteDecoratorA: Decorator {
    //A特有的装饰属性
    var addedState: String = ""
    
    override func operation() {
        super.operation()
        addedState = "new state"
        print("具体装饰对象A的操作")
    }
}

class ConcreteDecoratorB: Decorator {
    override func operation() {
        super.operation()
        addedBehavior()
        print("具体装饰对象B的操作")
    }
    //B特有的装饰方法
    func addedBehavior() { }
}

Code V3.0

使用装饰模式来实现这个需求是比较合适的。有效的把类的核心职责和装饰功能区分开了,还可以去除相关类中重复的装饰逻辑。但要注意某些场景要求调用的前后顺序。

static func showDecorator() {
    let ming = Person(name: "小明")
    
    print("第一种装扮")
    let wearTShirt = TShirt(component: ming)
    let wearBigTrouser = BigTrouser(component: wearTShirt)
    let wearSneaker = Sneaker(component: wearBigTrouser)
    wearSneaker.show()
    
    print("")
    print("第二种装扮")
    let wearSuit = Suit(component: ming)
    let wearTie = Tie(component: wearSuit)
    let wearLeatherShoes = LeatherShoes(component: wearTie)
    wearLeatherShoes.show()
}

class Person {
    var name: String = ""
    
    init() { }
    init(name: String) {
        self.name = name
    }
    
    func show() {
        print("装扮的\(name)")
    }
}

class Finery: Person {
    var component: Person?
    
    convenience init(component: Person) {
        self.init()
        self.component = component
    }
    
    override func show() {
        component?.show()
    }
}

class TShirt: Finery {
    override func show() {
        print("大T恤")
        super.show()
    }
}

class BigTrouser: Finery {
    override func show() {
        print("大垮裤")
        super.show()
    }
}

class Sneaker: Finery {
    override func show() {
        print("破球鞋")
        super.show()
    }
}

class Suit: Finery {
    override func show() {
        print("西装")
        super.show()
    }
}

class Tie: Finery {
    override func show() {
        print("领带")
        super.show()
    }
}

class LeatherShoes: Finery {
    override func show() {
        print("皮鞋")
        super.show()
    }
}