GoF 歸納整理的23個設(shè)計模式依據(jù)其目的可以分為創(chuàng)建型(Creational)豺旬、結(jié)構(gòu)型(Structural)和行為型(Behavioral)三種跃闹。關(guān)于創(chuàng)建型模式上次我已經(jīng)寫過一篇文章了尘吗,這次就說一說結(jié)構(gòu)型模式急黎。
顧名思義鳖枕,結(jié)構(gòu)型模式的目的主要就是組合類和對象以獲得一個更大更合適的結(jié)構(gòu)庄敛,具體包括適配器模式、橋接模式沽讹、組合模式般卑、裝飾者模式、外觀模式爽雄、享元模式和代理模式蝠检。本文主要介紹前三種模式,剩余的留待下期再論挚瘟。
適配器(Adapter)
適配器模式的目的是在不改變已有類(被適配者)的前提下叹谁,用一個新類(適配器)去繼承或者組合它,然后對外提供符合需求的接口乘盖。
設(shè)計模式的分類遵從目的準則和范圍準則焰檩,像創(chuàng)建型、結(jié)構(gòu)型订框、行為型這樣的分法是基于目的準則的析苫,而像類模式、對象模式這樣的分法則是基于范圍準則。類模式是指那些主要針對類衩侥,使用繼承來實現(xiàn)的模式国旷;對象模式是指那些主要使用對象組合來實現(xiàn)的模式。對象模式可以在運行期改變對象組合茫死,所以比類模式更靈活更動態(tài)跪但。適配器模式可以通過多繼承和對象組合實現(xiàn),所以說適配器模式既可以是類模式璧榄,也可以是對象模式特漩。
以 Swift 舉個例子(Swift 不支持多繼承吧雹,但支持實現(xiàn)多個協(xié)議):
protocol Animal {
//...
func move()
}
class Bird {
//...
func fly() {
print("Bird is flying.")
}
}
func playWithAnimal(animal: Animal) {
print("----Play----")
animal.move()
}
假設(shè)Bird
是一個早已存在的類骨杂,我們現(xiàn)在想把讓它用到playWithAnimal
這個方法里去,但顯然是不能直接用的雄卷,當然也不能輕易去修改它搓蚪,因為它可能跟很多其他的類有關(guān)聯(lián),一旦輕易修改就可能造成連鎖 Bug丁鹉。這個時候就可以讓適配器模式來一展拳腳了妒潭。
首先,我們使用類適配器揣钦,新建一個BirdAdapter
繼承Bird
:
class BirdClassAdapter: Bird, Animal {
func move() {
fly()
}
}
let bird = BirdClassAdapter()
playWithAnimal(bird)
這樣就可以正常調(diào)用了雳灾,而且不會影響到原有的類。
接下來我們使用對象適配器冯凹,新建一個BirdAdapter
來組合Bird
對象:
class BirdObjectAdapter: Animal {
var bird: Bird
init(bird: Bird) {
self.bird = bird
}
func move() {
bird.fly()
}
}
let bird = BirdObjectAdapter(bird: Bird())
playWithAnimal(bird)
類適配器可以在適配器中重寫Bird
類的方法谎亩,而且可以做到雙重適配,也就是說在原先用到Bird
類的地方也可以使用BirdClassAdapter
宇姚,這點是對象適配器做不到的匈庭。但對象適配器可以適配Bird
的所有子類,即在初始化BirdObjectAdapter
時可以傳入Bird
及其子類浑劳。
橋接模式(Bridge)
橋接模式的目的是為了將抽象部分與實現(xiàn)部分分離阱持,使它們可以獨立變化,以適應(yīng)系統(tǒng)的不斷發(fā)展魔熏。所以與適配器模式不同衷咽,橋接模式一般是在系統(tǒng)設(shè)計之初就開始使用以應(yīng)對未來的變化,而不是在一個已經(jīng)存在很久的舊系統(tǒng)中做一些修修補補的適配工作蒜绽。
橋接模式的形式其實也很簡單镶骗,就是利用對象組合分離接口和實現(xiàn),用繼承來分別擴充接口和實現(xiàn):
// 抽象(暴露給客戶使用的接口)
class Abstraction {
var imp: Implementor
init(imp: Implementor) {
self.imp = imp
}
func operation() {
imp.operationImp()
}
}
// 對接口的擴展
class RefinedAbstraction: Abstraction {
func otherOperation() {}
}
// 實現(xiàn)
protocol Implementor {
func operationImp()
}
// 對實現(xiàn)的擴展
class ConcreteImplementor: Implementor {
func operationImp() {
print("Do something.")
}
}
Abstraction
和Implementor
之間就是所謂的橋接關(guān)系滓窍,兩者可以獨立變化卖词,并隱藏大量實現(xiàn)細節(jié)。
組合(Composite)
Composite 模式(翻譯成組合模式總感覺怪怪的)將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),使單個對象和組合對象對外表現(xiàn)出一致的接口此蜈。
上圖是 Composite 模式的典型結(jié)構(gòu)圖即横,Composite
表示組合對象,Leaf
表示單個對象裆赵,都繼承自Component
(圖中未出現(xiàn))东囚。Component
是對外提供的接口,它一般包含Add(Component)
战授、Remove(Component)
页藻、GetChild(int)
以及通用的Operation()
等方法≈怖迹看到這里是不是感覺有點眼熟份帐?其實 iOS 開發(fā)者整天都在跟 Composite 模式打交道,因為 UIKit 就是基于 Composite 模式構(gòu)建的楣导。UIView 就是 Component废境,UIView 的所有子類,比如 UIImage筒繁、UILabel 等等噩凹,都既可以作為 Composite 又可以作為 Leaf。