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)生大量的不同的類—可怕的事情么鹤。
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如圖:
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):
- 比靜態(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è)特性脂信。
- 避免在層次結(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é)爷速。
- Decorator與它的Component不一樣 Decorator是一個(gè)透明的包裝。如果我們從對(duì)象標(biāo)識(shí)的觀點(diǎn)出發(fā),一個(gè)被裝飾了的組件與這個(gè)組件是有差別的,因此,使用裝飾不應(yīng)該依賴對(duì)象標(biāo)識(shí)磺浙。
- 有許多小對(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ò)也很困難。
8. 實(shí)現(xiàn)
swift 案例 裝飾模式UML圖
抽象基類
//抽象基類
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流程
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())")