人在IT江湖飄,不懂設計模式咋裝X?
橋接模式在日常開發中不是特别常用,主要是因為上手難度較大,但是對于了解面向對象設計有非常大的幫助。
橋接模式是将抽象部分與它的實作部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱為柄體(Handle and Body)模式或接口(Interfce)模式。
橋我們大家都熟悉,顧名思義就是用來将河的兩岸聯系起來的。而此處的橋是用來将兩個獨立的結構聯系起來,而這兩個被聯系起來的結構可以獨立的變化,所有其他的了解隻要建立在這個層面上就會比較容易。
下面是一些官方的說明,比較晦澀,必須等你有一定的經驗後才能了解: 1. 如果一個系統需要在抽象化和具體化之間增加更多的靈活性,避免在兩個層次之間建立靜态的繼承關系,通過橋接模式可以使它們在抽象層建立一個關聯關系。
“抽象部分”和“實作部分”可以以繼承的方式獨立擴充而互不影響,在程式運作時可以動态将一個抽象化子類的對象和一個實作化子類的對象進行組合,即系統需要對抽象化角色和實作化角色進行動态耦合。
一個類存在兩個(或多個)獨立變化的次元,且這兩個(或多個)次元都需要獨立進行擴充。
對于那些不希望使用繼承或因為多層繼承導緻系統類的個數急劇增加的系統,橋接模式尤為适用。
在講政策模式的時候,王二狗和牛翠花不是要到天津之眼去約炮,不,約會嘛,兩人到那後先去星巴克喝咖啡了,星巴克提供了多種選擇,從容量上說有大杯,中杯,小杯,從口味上說有原味,加糖,這可難為了有選擇恐懼症的牛翠花,半天點不出來,後面的人都開始罵娘了,王二狗也隻能陪着笑臉道歉。 其實被難為的除了牛翠花,還有給星巴克做訂單系統的外包公司的程式員林蛋大。一開始提需求的時候星巴克說我們隻有正常杯(中杯),原味和加糖這幾種選擇,人家林蛋大也是有兩年工作經驗的碼農,這需求不在話下,蛋大還想到了要面對抽象程式設計。
首先定義一個點咖啡接口,裡面有一個下單方法,至于點哪種口味的咖啡,就由其子類去決定,完美,蛋大好牛逼啊!
原味咖啡類
加糖咖啡類
搞定收工,王者榮耀搞起!項目經理突然過來了:蛋大啊,客戶那邊說了,他們準備加兩個容量規格的咖啡,大杯和小杯,你改一下。林蛋大:what?尼瑪為什麼不早說,老子剛寫完。胸中雖有萬千牢騷,還不得平複一下心情去改代碼,何必呢?蛋大心中暗喜,幸好老子是面向抽象程式設計的,對應加幾個實作類不就得了?
加着加着蛋大慌了,共需要3x2=6個類啊,大杯原味和加糖,中杯原味和加糖,小杯原味和加糖。過段時間萬一那二筆客戶又要出加奶,加蜂蜜等等口味,說不定還有迷你杯,女神杯等等規格的咖啡,那我這邊的類不就爆炸了嗎?看來的去找個設計模式了。。。
此場景橋接模式正合适,這裡有兩個變化次元,咖啡的容量和口味,而且都需要獨立變化。如果使用繼承的方式,随着變化類就會急劇的增加。你可以将容量了解為抽象部分,而口味了解為實作部分,這兩個部分需要橋接。
橋接模式UML 圖如下

橋梁模式所涉及的角色有:
抽象化(Abstraction)角色:抽象化給出的定義,并儲存一個對實作化對象的引用。
修正抽象化(RefinedAbstraction)角色:擴充抽象化角色,改變和修正父類對抽象化的定義。
實作化(Implementor)角色:這個角色給出實作化角色的接口,但不給出具體的實作。必須指出的是,這個接口不一定和抽象化角色的接口定義相同,實際上,這兩個接口可以非常不一樣。實作化角色應當隻給出底層操作,而抽象化角色應當隻給出基于底層操作的更高一層的操作。
具體實作化(ConcreteImplementor)角色:這個角色給出實作化角色接口的具體實作。
抽象化角色就像是一個水杯的搖桿,而實作化角色和具體實作化角色就像是水杯的杯身。搖桿控制杯身,這就是此模式别名“柄體”的來源。
林蛋大查了半天不知道使用哪個設計模式,隻能求助前輩王二狗了。電話通了:狗哥,我這有個問題。。。王二狗:我這正解決終身大事呢,沒工夫理你,你去調查一下橋接模式。林蛋大:不愧是大神,改天請你和嫂子吃飯,先挂啦。挂電話後,蛋大就開始用橋接模式重構代碼了。
蛋大分析了目前業務場景,認為可以将咖啡的容量作為抽象化Abstraction,而咖啡口味為實作化Implementor
第一步:建立抽象化部分:
我們可以看到,<code>Coffee</code>持有了<code>ICoffeeAdditives</code> 引用,<code>ICoffeeAdditives</code> 的執行個體是通過構造函數注入的,這個過程就是我們所說的橋接過程。我們通過這個引用就可以調用<code>ICoffeeAdditives</code>的方法,進而将<code>Coffee</code>的行為與<code>ICoffeeAdditives</code>的行為通過<code>orderCoffee()</code>方法而組合起來。
下面是一個對抽象化修正的一個類,裡面增加了一個品控的方法
第二步:建立實作化部分
第三步:用戶端調用
輸出結果:
通過使用橋接模式,就使得咖啡的容量和口味這兩個次元可以獨立變化,互不幹擾。林蛋大終于完成了代碼的重構,回頭一看王者榮耀由于惡意挂機被扣除15個信用分,暫時不能進行排位賽,無奈隻能再去鞏固一下橋接模式了。
優點:
分離抽象接口及其實作部分。橋接模式使用“對象間的關聯關系”解耦了抽象和實作之間固有的綁定關系,使得抽象和實作可以沿着各自的次元來變化。所謂抽象和實作沿着各自次元的變化,也就是說抽象和實作不再在同一個繼承層次結構中,而是“子類化”它們,使它們各自都具有自己的子類,以便任何組合子類,進而獲得多元度組合對象。
在很多情況下,橋接模式可以取代多層繼承方案,多層繼承方案違背了“單一職責原則”,複用性較差,且類的個數非常多,橋接模式是比多層繼承方案更好的解決方法,它極大減少了子類的個數。
橋接模式提高了系統的可擴充性,在兩個變化次元中任意擴充一個次元,都不需要修改原有系統,符合“開閉原則”。
缺點:
橋接模式的使用會增加系統的了解與設計難度,由于關聯關系建立在抽象層,要求開發者一開始就針對抽象層進行設計與程式設計。
橋接模式要求正确識别出系統中兩個獨立變化的次元,是以其使用範圍具有一定的局限性,如何正确識别兩個獨立次元也需要一定的經驗積累。
經過此次事件,林蛋大對王二狗的敬佩又多了幾分,二狗哥真乃神人也,不僅代碼寫的好,還能找到女朋友!
設計模式值得你刻意練習!