場景
飯店點餐一般有倆種方式,一種是單點港华,一種是套餐,如果單點我們需要面對菜單上所有的菜午衰,如果有了套餐立宜,我只需要點一個合適的套餐就可以,因為有套餐的存在臊岸,所以客戶不需要直接對應(yīng)菜單所有的菜橙数,只與套餐交互即可,整個過程簡單省事
單點帅戒、套餐
問題來了
在軟件開發(fā)中灯帮,有時候為了完成一項較為復(fù)雜的功能,一個客戶類需要和多個業(yè)務(wù)類交互,而這些需要交互的業(yè)務(wù)類經(jīng)常會作為一個整體出現(xiàn)钟哥,由于涉及到的類比較多迎献,導(dǎo)致使用時代碼較為復(fù)雜
問題改進(jìn)
為了避免客戶類需要和多個業(yè)務(wù)類交互,需要一個類似套餐一樣的角色瞪醋,由它來負(fù)責(zé)和多個業(yè)務(wù)類進(jìn)行交互忿晕,而客戶類只需與該類交互即可
表述 (結(jié)構(gòu)型模式)
為子系統(tǒng)中的一組接口提供一個統(tǒng)一的接口。外觀模式定義了一個更高層次的接口银受,這個接口使得這一子系統(tǒng)更加容易使用
外觀模式中践盼,一個子系統(tǒng)的外部與其內(nèi)部的通信通過一個統(tǒng)一的外觀類進(jìn)行,外觀類將客戶類與子系統(tǒng)的內(nèi)部復(fù)雜性分隔開宾巍,使得客戶類只需要與外觀角色打交道咕幻,而不需要與子系統(tǒng)內(nèi)部的很多對象打交道。
外觀模式類圖
外觀模式類圖
- Facade(外觀角色):就是表述中的“高層接口”顶霞,客戶端可以調(diào)用這個角色的方法肄程;另外,該角色知道相關(guān)的子系統(tǒng)的功能和責(zé)任
- SubSystem(子系統(tǒng)角色):在軟件系統(tǒng)中可以有一個或者多個子系統(tǒng)角色选浑,每一個子系統(tǒng)可以不是一個單獨的類蓝厌,而是一個類的集合,它實現(xiàn)子系統(tǒng)的功能古徒;每一個子系統(tǒng)都可以被客戶端直接調(diào)用拓提,或者被外觀角色調(diào)用,它處理由外觀類傳過來的請求隧膘;子系統(tǒng)并不知道外觀的存在代态,對于子系統(tǒng)而言,外觀角色僅僅是另外一個客戶端而已
優(yōu)點
- 它對客戶端屏蔽了子系統(tǒng)組件疹吃,減少了客戶端所需處理的對象數(shù)目蹦疑,并使得子系統(tǒng)使用起來更加容易
- 它實現(xiàn)了子系統(tǒng)與客戶端之間的松耦合關(guān)系,這使得子系統(tǒng)的變化不會影響到調(diào)用它的客戶端萨驶,只需要調(diào)整外觀類即可
缺點
- 不能很好地限制客戶端直接使用子系統(tǒng)類歉摧,如果對客戶端訪問子系統(tǒng)類做太多的限制則減少了可變性和靈活性
使用場景
- 當(dāng)要為訪問一系列復(fù)雜的子系統(tǒng)提供一個簡單入口時可以使用外觀模式
- 客戶端程序與多個子系統(tǒng)之間存在很大的依賴性。引入外觀類可以將子系統(tǒng)與客戶端解耦篡撵,從而提高子系統(tǒng)的獨立性和可移植性
示例
class ColdDish {
func log() {
print("涼菜")
}
}
class HotDish {
func log() {
print("熱菜")
}
}
class StapleFood {
func log() {
print("主食")
}
}
class MenuPackage {
var coldDish : ColdDish
var hotDish : HotDish
var stapleFood : StapleFood
init() {
self.coldDish = ColdDish()
self.hotDish = HotDish()
self.stapleFood = StapleFood()
}
func eat() {
self.coldDish.log()
self.hotDish.log()
self.stapleFood.log()
}
}
客戶端調(diào)用:
let menuPackage = MenuPackage()
menuPackage.eat()
log:
//涼菜
//熱菜
//主食