介紹
橋接模式(Bridge Pattern) 也稱為橋梁模式撩轰,是結(jié)構(gòu)型設(shè)計模式之一卜范。橋接模式的作用就是連接 "兩邊"
定義
將抽象部分與實現(xiàn)部分分離巧号,使他們都可以獨立地進行變化
定義看起來跟橋接沒有一毛錢關(guān)系慢蜓,但是別著急,慢慢往下看。
使用場景
先舉個例子傲诵,要不 抽象部分 跟 實現(xiàn)部分 真的會亂耽装。
比如去星巴克買的咖啡(媽蛋,不知道誰買,反正我是一杯都買不起)矾睦,最簡單的晦款,分大杯小杯,這里的大杯小杯就是咖啡的一個維度顷锰。再分還有加糖不加糖柬赐,這里的加糖不加糖又是咖啡這個東西的一個維度。
大小杯跟是否加糖是兩個互不影響相互獨立的維度官紫。
如果我們把咖啡定義為一個抽象類肛宋,大杯咖啡或者小杯咖啡分別為具體實現(xiàn)類,那么束世,加糖不加糖這個維度怎么處理酝陈?我們可能會想到,繼續(xù)繼承大杯或者小杯毁涉,然后分別定義不同的加糖不加糖的類沉帮,瞬間,兩個實現(xiàn)類就變成了四個贫堰,如果這時候我們增加了中杯穆壕,那么就需要再多加三個類。這還簡單其屏,如果這時候我們又加了糖分度喇勋,這時候繼承類的數(shù)量會瞬間爆炸,所以繼承不能解決問題偎行。
既然繼承不能解決問題川背,那我們還有沒有別的辦法? 當然有蛤袒,今天這個橋接模式解決的就是這類的問題熄云。
以加糖不加糖為例,我們把加糖不加糖這個維度抽象出一個接口,并且在咖啡類里面保持對一個加糖不加糖接口的引用妙真,在咖啡類的構(gòu)造方法中我們需要傳入是否加糖這個對象缴允,為接口對象賦值,并在咖啡類中用到是否加糖的方法時珍德,調(diào)用是否需要加糖這個引用的方法癌椿。
這樣就把是否加糖這個維度和大杯小杯這個維度分離開來,當大小杯變化比如增加中杯菱阵,加糖不加糖變化比如增加低度糖踢俄,這兩個變化就不會耦合在一起,可以獨立改變晴及。
這里的咖啡以及大小杯的咖啡子類就是抽象部分都办,加糖不加糖就是實現(xiàn)部分。這個如果不理解就先記住
使用場景
從模式的定義中我們大致了解到,這里的 “橋梁” 的作用就是連接 “抽象部分” 與 “實現(xiàn)部分” 琳钉,但是事實上势木,任何多維度變化類或者說多個樹狀類之間的耦合都可以使用橋接模式來實現(xiàn)解耦。
如果一個系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多靈活性歌懒,避免在這兩個層次之間建立靜態(tài)的繼承聯(lián)系啦桌,可以通過橋接模式使它們在抽象層建立一個關(guān)聯(lián)關(guān)系。
對于那些不希望使用繼承或因為多層繼承導致系統(tǒng)類的個數(shù)急劇增加的系統(tǒng)及皂,也可以考慮使用橋接模式
一個類存在兩個獨立變化的維度甫男,且這兩個維度都需要進行擴展
前面例子中的加糖和大小杯就是兩個維度,我們不希望通過分層繼承的方式解決验烧,所以使用橋接模式
角色介紹
Abstraction 抽象部分板驳,該類保持一個對實現(xiàn)部分對象的引用,抽象部分中的方法需要調(diào)用實現(xiàn)部分的對象的相關(guān)方法來實現(xiàn)碍拆,該類一般為一個抽象類
RefinedAbstraction 優(yōu)化的抽象部分若治,抽象部分的具體實現(xiàn),該類一般是對抽象部分的方法進行完善和擴展
Implementor 實現(xiàn)部分感混,可以為接口或者抽象類端幼,其方法不一定要與抽象部分中的一致,一般情況下是由實現(xiàn)部分提供基本的操作弧满,而抽象部分定義的則是基于實現(xiàn)部分這些基本操作的業(yè)務(wù)方法婆跑。
ConcreteImplementorA/ConcreteImolementorB 實現(xiàn)部分的具體實現(xiàn)
Client 客戶類,構(gòu)建實現(xiàn)部分的對象谱秽,根據(jù)實現(xiàn)部分的對象構(gòu)建抽象部分的對象洽蛀,最后調(diào)用抽象部分的方法完成業(yè)務(wù)摹迷。
Android 源碼中的橋接模式
在 View 的視圖層中的應(yīng)用
在 View 的視圖層級中疟赊,CheckBox、CompoundButton峡碉、Button近哟、TextView、View 之間過程了一個繼承關(guān)系層鲫寄,每一層都是對一種類型控件的描述吉执,其定義了該類所擁有的的基本屬性和行為。但是將他們真正繪制到屏幕上的部分是由與 View 相關(guān)的 DisplayList地来、Canvas 等硬件繪制部分負責戳玫,繪制這部分就是另一個維度,這兩部分的關(guān)系可以看做是對橋接模式的應(yīng)用未斑。
解釋一下:這里的抽象部分就是這些 View 的繼承關(guān)系層咕宿,不同的行為是一個維度,但是繪制的過程則是由 Canvas 等來實現(xiàn)的,繪制則是另一個維度府阀,相當于實現(xiàn)部分缆镣。兩個部分是不耦合的。
Adapter 與 AdapterView 直接的關(guān)系
Adapter 與 AdapterView 也可以看做是橋接模式试浙,AdapterView 的具體功能是一個維度董瞻,而獲取每個 item 顯示的內(nèi)容可以看做是另一個維度,這時候 AdapterView 是抽象部分田巴,Adapter 則是實現(xiàn)部分钠糊。抽象與實現(xiàn)不耦合。
橋接模式實戰(zhàn)
自定義一個進度條固额,有水平的眠蚂,豎直的,圓形的三種斗躏。那么繪制方式也就是有三種逝慧,我么此時可以將具體的繪制邏輯作為一個維度來提取出來,也就是定義一個抽象的進度條類啄糙,其中的抽象方法為繪制一個 View 所需的最少的成員屬性笛臣,再定義這個抽象進度條的三個子類,這三個子類分別完成三種不同形狀進度條的繪制隧饼。注意沈堡,這里的進度條繪制類并不是一個 View,只是實現(xiàn)了繪制的具體實現(xiàn)
在自定義的在 View 類中,持有對繪制類的對象引用燕雁,根據(jù)想要的進度條來實例繪制類的對象诞丽,在 view 的真正繪制方法中調(diào)用繪制類的對象的方法來實現(xiàn)。
此時拐格,自定義的 View 類就是橋接模式的抽象部分僧免,而繪制的部分就是實現(xiàn)部分。
其他實現(xiàn)
數(shù)據(jù)庫 dao 類的設(shè)計有時會使用橋接模式捏浊,如果對數(shù)據(jù)庫的一個訪問有不同的方式懂衩,這時候就可以把訪問方式作為一個維度來處理
Android 應(yīng)用層和 Native 層之間的交互也是橋接模式,在操縱硬件設(shè)備時就使用一個連接應(yīng)用層與 Native 層的橋梁金踪,這個橋梁通常是一個具體的類浊洞,比如提供操作相機的 Camera,播放音視頻的 MediaPlayer胡岔、提供圖形繪制接口的 OpenCV 等法希,這些 API 類為我們操作底層硬件提供了可能
總結(jié)
橋接模式可以應(yīng)用到許多開發(fā)中,但是應(yīng)用的并不多靶瘸,一個很主要的原因是對于抽象與實現(xiàn)分離的把握苫亦,是不是需要分離尖淘,如何分離?對于設(shè)計者來說要有一個恰到好處的分寸著觉。
優(yōu)點
分離抽象與實現(xiàn)村生,靈活的擴展以及對客戶來說透明的實現(xiàn)。
缺點
分離的分寸不容易把握