5撵术、裝飾模式

1. 概述

    若你從事過(guò)面向?qū)ο箝_(kāi)發(fā)逮光,實(shí)現(xiàn)給一個(gè)類或?qū)ο笤黾有袨椋褂美^承機(jī)制栖秕,這是所有面向?qū)ο笳Z(yǔ)言的一個(gè)基本特性春塌。
如果已經(jīng)存在的一個(gè)類缺少某些方法,或者須要給方法添加更多的功能(魅力)簇捍,
你也許會(huì)僅僅繼承這個(gè)類來(lái)產(chǎn)生一個(gè)新類—這建立在額外的代碼上只壳。
    通過(guò)繼承一個(gè)現(xiàn)有類可以使得子類在擁有自身方法的同時(shí)還擁有父類的方法。但是這種方法是靜態(tài)的暑塑,
用戶不能控制增加行為的方式和時(shí)機(jī)吼句。如果 你希望改變一個(gè)已經(jīng)初始化的對(duì)象的行為,你怎么辦事格?
或者惕艳,你希望繼承許多類的行為,該怎么辦?前一個(gè)分蓖,只能在于運(yùn)行時(shí)完成尔艇,后者顯然時(shí)可能的,
但是可能會(huì)導(dǎo)致產(chǎn)生大量的不同的類—可怕的事情么鹤。

demo地址终娃,歡迎star

2. 問(wèn)題

  你如何組織你的代碼使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接添加額外的代碼寫(xiě)在
你的類的內(nèi)部蒸甜?

3. 解決方案

?????? 裝飾器模式: 動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)或者行為棠耕。就增加功能來(lái)說(shuō), Decorator模式相比生成子類更為靈活柠新。

??????裝飾器模式提供了改變子類的靈活方案窍荧。裝飾器模式在不必改變?cè)愇募褪褂美^承的情況下,動(dòng)態(tài)的擴(kuò)展一個(gè)對(duì)象的功能恨憎。它是通過(guò)創(chuàng)建一個(gè)包裝對(duì)象蕊退,也就是裝飾來(lái)包裹真實(shí)的對(duì)象。

??????當(dāng)用于一組子類時(shí)憔恳,裝飾器模式更加有用瓤荔。如果你擁有一族子類(從一個(gè)父類派生而來(lái)),你需要在與子類獨(dú)立使用情況下添加額外的特性钥组,你可以使用裝飾器模式输硝,以避免代碼重復(fù)和具體子類數(shù)量的增加。

4. 適用性

以下情況使用Decorator模式

  • 在不影響其他對(duì)象的情況下程梦,以動(dòng)態(tài)点把、透明的方式給單個(gè)對(duì)象添加職責(zé)橘荠。
  • 處理那些可以撤消的職責(zé)。
  • 當(dāng)不能采用生成子類的方法進(jìn)行擴(kuò)充時(shí)郎逃。一種情況是哥童,可能有大量獨(dú)立的擴(kuò)展,
    為支持每一種組合將產(chǎn)生大量的子類褒翰,使得子類數(shù)目呈爆炸性增長(zhǎng)如蚜。
    另一種情況可能是因?yàn)轭惗x被隱藏,或類定義不能用于生成子類影暴。

5. 結(jié)構(gòu)

UML如圖:

裝飾模式.jpg

6.構(gòu)建模式的組成

抽象組件角色(Component):定義一個(gè)對(duì)象接口,以規(guī)范準(zhǔn)備接受附加責(zé)任的對(duì)象探赫,即可以給這些對(duì)象動(dòng)態(tài)地添加職責(zé)型宙。
具體組件角色(ConcreteComponent) :被裝飾者,定義一個(gè)將要被裝飾增加功能的類伦吠。
可以給這個(gè)類的對(duì)象添加一些職責(zé)
抽象裝飾器(Decorator):維持一個(gè)指向構(gòu)件Component對(duì)象的實(shí)例妆兑,
并定義一個(gè)與抽象組件角色Component接口一致的接口
具體裝飾器角色(ConcreteDecorator):向組件添加職責(zé)。

7. 效果

裝飾模式的特點(diǎn):
1) 裝飾對(duì)象和真實(shí)對(duì)象有相同的接口毛仪。這樣客戶端對(duì)象就可以以和真實(shí)對(duì)象相同的方式和裝飾對(duì)象交互搁嗓。
2) 裝飾對(duì)象包含一個(gè)真實(shí)對(duì)象的索引(reference) 
3) 裝飾對(duì)象接受所有的來(lái)自客戶端的請(qǐng)求。它把這些請(qǐng)求轉(zhuǎn)發(fā)給真實(shí)的對(duì)象箱靴∠俟洌  
4) 裝飾對(duì)象可以在轉(zhuǎn)發(fā)這些請(qǐng)求以前或以后增加一些附加功能。這樣就確保了在運(yùn)行時(shí)衡怀,不用修改給定對(duì)象的結(jié)構(gòu)就可以在外部增加附加的功能棍矛。在面向?qū)ο蟮脑O(shè)計(jì)中,通常是通過(guò)繼承來(lái)實(shí)現(xiàn)對(duì)給定類的功能擴(kuò)展抛杨。

Decorator模式至少有兩個(gè)主要優(yōu)點(diǎn)和兩個(gè)缺點(diǎn):

  1. 比靜態(tài)繼承更靈活: 與對(duì)象的靜態(tài)繼承(多重繼承)相比够委, Decorator模式提供了更加靈活的向?qū)ο筇砑勇氊?zé)的方式〔老郑可以用添加和分離的方法茁帽,用裝飾在運(yùn)行時(shí)刻增加和刪除職責(zé)。相比之下屈嗤,繼承機(jī)制要求為每個(gè)添加的職責(zé)創(chuàng)建一個(gè)新的子類潘拨。這會(huì)產(chǎn)生許多新的類,并且會(huì)增加系統(tǒng)的復(fù)雜度恢共。此外战秋,為一個(gè)特定的Component類提供多個(gè)不同的 Decorator類,這就使得你可以對(duì)一些職責(zé)進(jìn)行混合和匹配讨韭。使用Decorator模式可以很容易地重復(fù)添加一個(gè)特性脂信。
  2. 避免在層次結(jié)構(gòu)高層的類有太多的特征 Decorator模式提供了一種“即用即付”的方法來(lái)添加職責(zé)癣蟋。它并不試圖在一個(gè)復(fù)雜的可定制的類中支持所有可預(yù)見(jiàn)的特征,相反狰闪,你可以定義一個(gè)簡(jiǎn)單的類疯搅,并且用 Decorator類給它逐漸地添加功能÷癖茫可以從簡(jiǎn)單的部件組合出復(fù)雜的功能幔欧。這樣,應(yīng)用程序不必為不需要的特征付出代價(jià)。同時(shí)更易于不依賴于 Decorator所擴(kuò)展(甚至是不可預(yù)知的擴(kuò)展)的類而獨(dú)立地定義新類型的 Decorator。擴(kuò)展一個(gè)復(fù)雜類的時(shí)候卧波,很可能會(huì)暴露與添加的職責(zé)無(wú)關(guān)的細(xì)節(jié)爷速。
  3. Decorator與它的Component不一樣 Decorator是一個(gè)透明的包裝。如果我們從對(duì)象標(biāo)識(shí)的觀點(diǎn)出發(fā),一個(gè)被裝飾了的組件與這個(gè)組件是有差別的,因此,使用裝飾不應(yīng)該依賴對(duì)象標(biāo)識(shí)磺浙。
  4. 有許多小對(duì)象 采用Decorator模式進(jìn)行系統(tǒng)設(shè)計(jì)往往會(huì)產(chǎn)生許多看上去類似的小對(duì)象,這些對(duì)象僅僅在他們相互連接的方式上有所不同徒坡,而不是它們的類或是它們的屬性值有所不同撕氧。盡管對(duì)于那些了解這些系統(tǒng)的人來(lái)說(shuō),很容易對(duì)它們進(jìn)行定制喇完,但是很難學(xué)習(xí)這些系統(tǒng)伦泥,排錯(cuò)也很困難。

demo地址何暮,歡迎star

8. 實(shí)現(xiàn)

swift 案例 裝飾模式UML圖

裝飾模式.png

抽象基類

//抽象基類
class Component: NSObject {
    func show() { 
    }
}

人類

//人類(被裝飾對(duì)象)
class Person: Component {
    private var name: String;
    
    init(name: String) {
        self.name = name
        super.init()
    }
    
    override func show() {
        print("裝扮的\(name)")
    }
}

服飾基類

//服飾基類
class Finery: Component {
    private var component: Component?
    func decorate(component: Component) {
        self.component = component
    }
    
    override func show() {
        guard let component = component else { return }
        component.show()
    }
}

服飾子類(其它子類類似)

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


9. 實(shí)現(xiàn)2

因?yàn)橹挥幸粋€(gè)具體被裝飾類奄喂,所以可以除去抽象基類Component,以Person類作為抽象基類

(抽象基類)

//人類(被裝飾對(duì)象)
class Person: Component {
    private var name: String;
    
    init(name: String) {
        self.name = name
        super.init()
    }
    
    override func show() {
        print("裝扮的\(name)")
    }
}

服飾基類(服飾子類不作改動(dòng))

//服飾基類
class Finery: Component {
    
    private var component: Component?
    
    func decorate(component: Component) {
        self.component = component
    }
    
    override func show() {
        guard let component = component else { return }
        component.show()
    }
}

10. HeadFirst流程

裝飾模式-1.jpg

11. HeadFirst實(shí)現(xiàn)

Beverage協(xié)議

//接口海洼,swift沒(méi)有抽象類跨新,只能用協(xié)議實(shí)現(xiàn)
protocol Beverage {
    var description: String { set get }
    func getDescription() -> String
    func cost() -> Double
}

////抽象基類  錯(cuò)誤方式
//class Beverage {
//    var description = "Unknown Beverage"
//
//    func getDescription() -> String { return description }
//
//    func cost() -> Double { return 0.0 }
//}

調(diào)料基類

class CondimentDecorator: Beverage {
    var description: String = "Unknown Condiment"

    func getDescription() -> String { return description }

    func cost() -> Double { return 0.0  }
}

濃縮咖啡(具體飲料,其它飲料類型)

class CondimentDecorator: Beverage {
    var description: String = "Unknown Condiment"

    func getDescription() -> String { return description }

    func cost() -> Double { return 0.0  }
}

調(diào)料

//豆?jié){
class Soy: CondimentDecorator {
    var beverage: Beverage

    init(beverage: Beverage) {
        self.beverage = beverage
    }

    override func getDescription() -> String { return beverage.getDescription() + ", Soy" }

    override func cost() -> Double { return 0.15 }
}

具體實(shí)現(xiàn)

//深縮咖啡: 不加調(diào)料
let epresso = Espresso()
print("\(epresso.getDescription()) $\(epresso.cost())")

//深焙咖啡: 兩杯摩卡坏逢,一杯奶泡
var darkRoast: Beverage = DarkRoast()
darkRoast = Mocha(beverage: darkRoast)
darkRoast = Mocha(beverage: darkRoast)
darkRoast = Whip(beverage: darkRoast)
print("\(darkRoast.getDescription()) $\(darkRoast.cost())")

demo地址域帐,歡迎star

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市是整,隨后出現(xiàn)的幾起案子肖揣,更是在濱河造成了極大的恐慌,老刑警劉巖浮入,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件龙优,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡事秀,警方通過(guò)查閱死者的電腦和手機(jī)彤断,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)野舶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人宰衙,你說(shuō)我怎么就攤上這事平道。” “怎么了供炼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵一屋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我袋哼,道長(zhǎng)冀墨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任涛贯,我火速辦了婚禮轧苫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疫蔓。我一直安慰自己,他們只是感情好身冬,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布衅胀。 她就那樣靜靜地躺著,像睡著了一般酥筝。 火紅的嫁衣襯著肌膚如雪滚躯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,792評(píng)論 1 290
  • 那天嘿歌,我揣著相機(jī)與錄音掸掏,去河邊找鬼。 笑死宙帝,一個(gè)胖子當(dāng)著我的面吹牛丧凤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播步脓,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼愿待,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了靴患?” 一聲冷哼從身側(cè)響起仍侥,我...
    開(kāi)封第一講書(shū)人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸳君,沒(méi)想到半個(gè)月后农渊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡或颊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年砸紊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了传于。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡批糟,死狀恐怖格了,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情徽鼎,我是刑警寧澤盛末,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站否淤,受9級(jí)特大地震影響悄但,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜石抡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一檐嚣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啰扛,春花似錦嚎京、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至煞茫,卻和暖如春帕涌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背续徽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工蚓曼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钦扭。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓纫版,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親客情。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捎琐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容