IOS设计模式浅析之桥接模式(Bridge)
引言
在項(xiàng)目開(kāi)發(fā)中,我們會(huì)遇到這樣的一種場(chǎng)景:某些類(lèi)型由于自身的邏輯,往往具有兩個(gè)或多個(gè)維度的變化,比如說(shuō)大話設(shè)計(jì)模式書(shū)中所說(shuō)的手機(jī),它有兩個(gè)變化的維度:一是手機(jī)的品牌,可能有三星、蘋(píng)果等;二是手機(jī)上的軟件,可能有QQ、微信等。如何應(yīng)對(duì)這種“多維度的變化”?怎樣利用面向?qū)ο蟮募夹g(shù)來(lái)使得該類(lèi)型能夠輕松的沿著多個(gè)方向進(jìn)行變化,而又不引入額外的復(fù)雜度?這就是本章橋接模式所要解決的問(wèn)題。
定義
“將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化”
最初的定義出現(xiàn)于《設(shè)計(jì)模式》(Addison-Wesley,1994)。
光看這個(gè)定義,很抽象,也很不好理解。我們換一種容易理解的方式來(lái)說(shuō)明一下:假設(shè)有一個(gè)系統(tǒng),它可以使用多種方式來(lái)進(jìn)行分類(lèi),并且每一種分類(lèi)都有可能變化(比如說(shuō)上面說(shuō)的手機(jī),既可以按照手機(jī)品牌來(lái)分類(lèi),也可以按照手機(jī)軟件來(lái)分類(lèi),兩者都是有可能變化的),那么就把這些分類(lèi)方式分離出來(lái)讓它們獨(dú)立的變化,以減少它們之間的耦合。
結(jié)構(gòu)圖
我們先來(lái)說(shuō)明一下結(jié)構(gòu)圖中的各個(gè)部分:
Abstraction:定義中所說(shuō)的抽象部分,通常在這個(gè)對(duì)象里面,要維護(hù)一個(gè)實(shí)現(xiàn)部分的對(duì)象引用,在抽象對(duì)象里面的方法,需要調(diào)用實(shí)現(xiàn)部分的對(duì)象來(lái)完成。這個(gè)對(duì)象里面的方法,通常都是跟具體的業(yè)務(wù)相關(guān)的方法。在上面手機(jī)的例子中,可以理解為手機(jī)品牌接口;
Implementor:定義中所說(shuō)的實(shí)現(xiàn)部分,這個(gè)接口不用和Abstraction里面的方法一致,通常是由Implementor接口提供基本的操作,而Abstraction里面定義的是基于這些基本操作的業(yè)務(wù)方法,也就是說(shuō)Abstraction定義了基于這些基本操作的較高層次的操作。在上面手機(jī)的例子中,可以理解為手機(jī)軟件接口(也可以是類(lèi));
RefinedAbstraction:抽象部分的具體實(shí)現(xiàn),通常在這個(gè)對(duì)象里面,定義跟實(shí)際業(yè)務(wù)相關(guān)的方法,這些方法的實(shí)現(xiàn)通常會(huì)使用Abstraction中定義的方法,也可能需要調(diào)用實(shí)現(xiàn)部分的對(duì)象來(lái)完成。在上面手機(jī)的例子中,可以理解為具體的手機(jī)品牌,它實(shí)現(xiàn)了Abstraction接口;
ConcreteImplementatorA:實(shí)現(xiàn)部分的具體實(shí)現(xiàn),在上面手機(jī)的例子中,可以理解為具體的手機(jī)軟件,它實(shí)現(xiàn)了(或繼承了) Implementor。
這樣角色一一對(duì)照之后,是不是比較清楚了?如果不清楚,那么下面給出手機(jī)這個(gè)例子用橋接模式實(shí)現(xiàn)的結(jié)構(gòu)圖,如下所示:
有人可能馬上發(fā)現(xiàn)這個(gè)圖和上面的結(jié)構(gòu)圖不太一樣,這正是橋接模式的優(yōu)點(diǎn):它把抽象部分從實(shí)現(xiàn)部分中分離出來(lái),使得兩部分能夠獨(dú)立變更。這樣,添加新的RefinedAbstraction(抽象部分的具體實(shí)現(xiàn)),對(duì)Implementor(實(shí)現(xiàn)部分)不會(huì)有任何影響;同樣,添加新的ConcreteImplementatorC(實(shí)現(xiàn)部分的具體實(shí)現(xiàn)),也能做到不影響Abstraction(抽象部分)。
假設(shè)不使用橋接模式,那么我們做出的結(jié)構(gòu)圖可能有下面兩種(來(lái)自大話設(shè)計(jì)模式):
1.按品牌分類(lèi):
2.按軟件分類(lèi):
當(dāng)我們?cè)黾右粋€(gè)手機(jī)品牌HTC,按照品牌分類(lèi)的話我們需要增加手機(jī)品牌類(lèi)HTC,還需要增加兩個(gè)手機(jī)軟件類(lèi)HTC的QQ、HTC的微信;同樣,如果需要增加一個(gè)手機(jī)軟件,那么按照手機(jī)軟件分類(lèi)的話,我們也是需要增加三個(gè)類(lèi)。當(dāng)我們需要增加更多的手機(jī)品牌和手機(jī)軟件時(shí),我們會(huì)發(fā)現(xiàn)類(lèi)會(huì)越來(lái)越多,以致無(wú)法維護(hù)。另外,采用繼承的方式,子類(lèi)和父類(lèi)之間的耦合度是很高的,以至于父類(lèi)中的任何變化必然會(huì)導(dǎo)致子類(lèi)發(fā)生變化。這種依賴(lài)關(guān)系限制了靈活性并最終限制了復(fù)用性(《設(shè)計(jì)模式》)
示例
上面手機(jī)的示例,這里就不用代碼進(jìn)行說(shuō)明了。大話設(shè)計(jì)模式書(shū)上有C#版本的示例代碼,很好理解。這里還是繼續(xù)抽象工廠模式中的應(yīng)用場(chǎng)景:繪圖有兩個(gè)變化維度,一是工具,可以用HTML5、OWC等;另一個(gè)是圖形的種類(lèi),我們可能需要繪制餅狀圖、線形圖等。下面給出采用橋接模式實(shí)現(xiàn)的結(jié)構(gòu)圖,如下所示:
這里給出部分源碼,完整代碼可以自行下載附件。
Chart.h,這是一個(gè)協(xié)議,里面只定義了一個(gè)方法,用于繪制圖形:
1 @protocol Chart <NSObject> 2 3 - (void)draw;
LineChart.m(PieChart.m類(lèi)似),實(shí)現(xiàn)了Chart協(xié)議:
1 - (void)draw
2 {
3 NSLog(@"繪制線形圖");
4 }
Tool.h,一個(gè)協(xié)議,這個(gè)協(xié)議里面定義了一個(gè)Chart類(lèi)型的屬性和一個(gè)繪圖的方法(當(dāng)然,這個(gè)方法不是必須的,如果這個(gè)方法里面,你只是調(diào)用Chart的繪圖方法,那么久可以直接用Chart類(lèi)型的屬性去調(diào)用Chart的繪圖方法,這里加這個(gè)方法是考慮還有其他業(yè)務(wù)邏輯要處理的情況):
1 #import "Chart.h" 2 3 @protocol Tool <NSObject> 4 5 @property (nonatomic,assign) id<Chart> chart; 6 7 - (void)drawing;
HTML5.m(Owc.m類(lèi)似),實(shí)現(xiàn)了Tool協(xié)議:
1 @synthesize chart = _chart;
2
3 - (void)drawing
4 {
5 NSLog(@"HTML5 繪圖開(kāi)始......");
6
7 [_chart draw];
8
9 NSLog(@"HTML5 繪圖結(jié)束......");
10 }
客戶端調(diào)用代碼:
1 id<Tool> tool = [[[NSClassFromString(@"HTML5") alloc] init] autorelease]; 2 3 tool.chart = [[[NSClassFromString(@"LineChart") alloc] init] autorelease]; 4 5 [tool drawing];
輸出結(jié)果如下(省略時(shí)間及項(xiàng)目名):
HTML5 繪圖開(kāi)始......
繪制線形圖
HTML5 繪圖結(jié)束......
前面引言里面說(shuō)了,橋接模式解決了兩維或多維變化的問(wèn)題,結(jié)構(gòu)圖和上面的示例所講述的都是兩維,那么多維變化的又是怎么樣的呢?假設(shè)現(xiàn)在繪圖這個(gè)功能,需要支持不同的平臺(tái),比如說(shuō)要支持Windows平臺(tái)和Mac平臺(tái),那么結(jié)構(gòu)圖又是怎么樣的?下面給出這種情況下的橋接模式的結(jié)構(gòu)圖:
小結(jié)
橋接模式的優(yōu)點(diǎn):
橋接模式使用聚合關(guān)系,解耦了抽象和實(shí)現(xiàn)之間固有的綁定關(guān)系,使得抽象和實(shí)現(xiàn)可以沿著各自的維度來(lái)變化。
提高了系統(tǒng)的可擴(kuò)展性,可以獨(dú)立地對(duì)抽象部分和實(shí)現(xiàn)部分進(jìn)行擴(kuò)展。
可減少子類(lèi)的個(gè)數(shù),這個(gè)在前面講手機(jī)示例的時(shí)候進(jìn)行分析了。
橋接模式的缺點(diǎn):
橋接模式的引入會(huì)增加系統(tǒng)的理解與設(shè)計(jì)難度,由于聚合關(guān)系建立在抽象層,要求開(kāi)發(fā)者針對(duì)抽象進(jìn)行設(shè)計(jì)與編程。
橋接模式要求正確識(shí)別出系統(tǒng)中兩個(gè)獨(dú)立變化的維度,因此其使用范圍具有一定的局限性。
通過(guò)優(yōu)缺點(diǎn)的分析,我們可以在如下的情形下使用橋接模式:
不想在抽象與其實(shí)現(xiàn)之間形成固定的綁定關(guān)系;
抽象及其實(shí)現(xiàn)都應(yīng)可以通過(guò)子類(lèi)化獨(dú)立進(jìn)行擴(kuò)展;
對(duì)抽象的實(shí)現(xiàn)進(jìn)行修改不應(yīng)影響客戶端代碼;
如果每個(gè)實(shí)現(xiàn)需要額外的子類(lèi)以細(xì)化抽象,則說(shuō)明有必要把它們分成兩個(gè)部分;
想在帶有不同抽象接口的多個(gè)對(duì)象之間共享一個(gè)實(shí)現(xiàn)。
總的來(lái)說(shuō),橋接模式的本質(zhì)在于“分離抽象和實(shí)現(xiàn)”。
下載源碼 返回目錄
總結(jié)
以上是生活随笔為你收集整理的IOS设计模式浅析之桥接模式(Bridge)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CF思维联系–CodeForces -
- 下一篇: 汽水音乐怎么复制歌曲链接