十九、装饰模式(Decorator)

作者: LeeLeCoder | 来源:发表于2017-06-25 16:07 被阅读27次

    1. 何为装饰模式

    1.1 定义:

    在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

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

    装饰模式的结构图如图1-1所示:

    图1-1 装饰模式结构图

    1.2 装饰模式的特点:

    (1)装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
    (2)装饰对象包含一个真实对象的引用(reference)。
    (3)装饰对象接受所有来自客户端的请求,它把这些请求转发给真实的对象。
    (4)装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改改定对象的结构就可以增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

    2. 情景设置

    我们在买车时,有很多的车型(Suv, Mpv等等)供我们去选择,也有很多配件供我们去选择,要实现选择车型和车的配件这一过程,我们可以创建很多的类去实现。但是车型很多,车的配件更多,我们为每一种情况都去创建一个类,显然是不现实的。

    对于这种情景,使用装饰模式去解决无疑是一个很不错的选择。根据以上的描述我们将此场景抽象为下面的结构图,如图2-1所示:

    图2-1

    3. 代码实现

    // Component
    protocol Car {
        // 多少钱
        func howMuch()-> Int
        // 展示装配的配件
        func showParts()
    }
    
    // ConcreteComponents
    class Suv: Car {
        init(owner: String) {
            print("\(owner)买了一辆Suv,10W")
        }
        
        func howMuch() -> Int {
            return 10
        }
        
        func showParts() {}
    }
    
    class Mpv: Car {
        init(owner: String) {
            print("\(owner)买了一辆Mpv,15W")
        }
        func howMuch() -> Int {
            return 15
        }
        func showParts() {}
    }
    
    // Decorator
    class CarParts: Car {
        var car: Car?
        func howMuch() -> Int {
            return car?.howMuch() ?? 0
        }
        func showParts() {
            car?.showParts()
        }
        func decorator(_ car: Car) -> Car {
            self.car = car
            return self
        }
    }
    
    // ConcreteDecorators 
    class Sofa: CarParts {
        override func howMuch() -> Int {
            return super.howMuch() + 1
        }
        override func showParts() {
            super.showParts()
            print("选配了真皮沙发,1W")
        }
    }
    
    class Safety: CarParts {
        override func howMuch() -> Int {
            return super.howMuch() + 3
        }
        
        override func showParts() {
            super.showParts()
            print("选配了全套安全系统,3W")
        }
    }
    
    class Engine: CarParts {
        override func howMuch() -> Int {
            return super.howMuch() + 5
        }
        override func showParts() {
            super.showParts()
            print("选配了V8发动机,5W")
        }
    }
    

    客户端调用:

    // wc1买一辆suv
    var suv: Car = Suv(owner: "wc1")
    // 装配沙发
    suv = Sofa().decorator(suv)
    // 装配发动机
    suv = Engine().decorator(suv)
    // 装配安全系统
    suv = Safety().decorator(suv)
    suv.showParts()
    print("一共花了\(suv.howMuch())W")
    
    // wcl买一辆mpv
    var mpv: Car = Mpv(owner: "wcl")
    // 装配发动机
    mpv = Engine().decorator(mpv)
    // 装配安全系统
    mpv = Safety().decorator(mpv)
    mpv.showParts()
    print("一共花了\(mpv.howMuch())W")
    

    控制台输出:

    wc1买了一辆Suv, 10W 选配了真皮沙发,1W 选配了V8发动机,5W 选配了全套安全系统,3W 一共花了19W wcl买了一辆Mpv, 15W 选配了V8发动机,5W 选配了全套安全系统,3W 一共花了23W

    4. 装饰模式的优缺点

    优点:

    (1)可以将类中装饰功能从类中搬出去,简化原有的类
    (2)有效的将核心职责和装饰功能区分开来,而且可以除去相关类中重复的装饰逻辑

    缺点:

    (1)装饰模式虽然扩展性较高,类的数量较多,如何取舍可扩展性和间接性是个问题,有选择就要有所牺牲
    (2)很难搞清楚一个类究竟被装饰了多少层,可能是1层,也可能是100层

    相关文章

      网友评论

        本文标题:十九、装饰模式(Decorator)

        本文链接:https://www.haomeiwen.com/subject/yyvtcxtx.html