橋接模式是將抽象部分與它的實現部分分離,使它們均可以獨立地變化。它是一種對象結構型模式,又稱爲柄體[Handle and Body]模式或接口[Interfce]模式。 java
聽懂了這句話就不用往下看了,說明你會了。設計模式
聽不懂我以爲也正常,若是用一句話能學會就沒人看書了。像我這種笨人,都是學會了一個模式,而後往它的定義上套。函數
上面的概念中說到,抽象部分與它的實現(功能)部分分離,使它們均可以獨立地變化。看下面這句話:測試
類的層級結構只有一層,功能層次結構與實現層級結構是混雜在一個層級結構中時,你可使用橋接模式。 —— 《圖解設計模式》this
在說以前先說三個概念:spa
可能名詞比較陌生,我剛看的時候以爲好高大上啊,沒聽過的技術名詞都以爲高大上。設計
但這三個名詞用白話來描述就特別簡單。3d
用一句話就能說明白。code
類的層級結構就是類與子類之間的繼承的層數。對象
這個圖中類的層級結構的層數是:1
這個圖中類的層級結構的層數是:2
類的層級結構的層數不能太深。
類的功能層次結構,用一句話說不完,得兩句話。
首先兩個類有繼承關係。
父類具備一些基本功能,在子類中添加了新的功能,這就叫功能層次結構。
仍是不太好理解,我當時是這麼理解的,子類繼承了父類的方法以外,還有本身的方法,這種層次結構叫功能層次結構。例以下面的圖:
動物定義了呼吸方法,而後狗繼承了動物,狗還加了一個犬吠方法,這種層次結構就叫功能層次結構。
類的實現層次結構,也得用兩句話說明。
首先兩個類也有繼承關係。
父類經過抽象的方式來定義方法。而後子類經過實現父類的抽象方法來完成這個方法的具體實現。
簡單說就是一個類實現了父類的抽象方法。
動物定義了一個移動的抽象方法,狗實現了這個抽象方法,這種層次結構就叫實現層次結構。
類的層級結構只有一層,功能層次結構與實現層級結構混雜在一個層級結構中,這樣很容易讓類的設計變得複雜,也難以透徹地理解類的層次結構。由於本身也難以肯定究竟在類的哪個層次結構去增長新需求。
這個時候,能夠嘗試使用橋接模式,將抽象部分與它的實現部分分離,使它們均可以獨立地變化。
簡單說,就是怎麼作抽象部分與它的實現部分分離。
下面會以一個場景來講明,主要是兩件事:
先看來圖來講明:
類圖以奔馳車爲例作了一個模型,奔馳的車有不一樣的車系,每一個車系均可以遠程開門,而車系下的各個車的協議解析都不一樣。因此在車系中定義了遠程開關車門的抽象方法。由各個開門協議對象去實現本身的協議解析。
這種方法目前看沒有什麼問題,可是設計原則也好,設計模式也好,或者說設計工做,一個很重要任務就是要考慮到將來的需求變動。
那麼以這個圖做爲假設,需求變化成還有Benz的B、D、E系列的車,每一個下面有2個具體車型,那麼咱們就要加入3個抽象類,6個實現類,就比如下面的類圖:
就如上圖所示。上面的場景,從類的實現層次結構來說,每次實現的增長都成倍的增長類,最後會出現類爆炸的場面。加一個車系和對應的車型,就須要對應數量的類,好比B、D、E系列的車,每一個下面有5個具體車型,那麼咱們就要加入3 * 5 = 15個類。
相同的例子還有不少,好比有用畫國畫舉例的,畫國畫須要毛筆,要用到小號、中號、大號的毛筆,另外還須要水彩(12顏色)。組合起來是:顏色數量 * 毛筆型號數量 = 12 * 3 = 36,須要36(紅色小號、紅色中號、紅色大號,綠色小號 …… 黑色大號)個類。
若是需求變動了,增長了2種毛筆的型號,顏色也增長了12種,那麼本次新增的類就是2 * 24 = 48,一共須要5 * 24 = 120,共須要120個類,完成這個需求,這就是類爆炸!
其次,上面的場景,想要實現一些新的功能,難以決定加到哪一層級。
由於這種設計,把類的功能擴展和類的多態實現混到了一塊兒。混到一塊兒的後果就是維護起來比較模糊。
例如:某些車要加一些新的功能,好比所有開門、前排開門、後排開門,而後又要加一些的新的實現,好比所有開門協議,開前門協議,看後門協議。這樣代碼混到了一塊兒,職責不清晰,具體如圖:
圖中A系列的車系下的全部車型都有開門功能,所有開門功能,而後A200能夠只開前門,A300能夠只開後門。
在這種結構下擴展,只能將開門協議和開門動做放到一個類中,定義模糊。這就是所說的難以擴展。
通過橋接模式重構,獲得上面的類圖,將協議與車型分開,經過聚合的方式將車型與協議聯接在一塊兒,起到的重點是,分開後更容易擴展。當要增長新功能時,在類的功能層次結構(左側,車型側)增長便可,沒必要對類的實現層次結構(右側,協議側)進行修改。反之亦然。
上面的例子中,若是新增了A系列車的具體車型,不須要增長協議類,若是增長了開門協議,也不須要增長車型類(B型車,C型車……同A型車)。
上一小節說到的國畫需求也是同樣,左側能夠是毛筆和3中型號的毛筆類,右側是水彩和12種顏色的水彩類,加起來是15個類,添加毛筆型號不須要增長顏色一側的類,添加顏色也不須要增長毛筆一次的類。
測試Main方法,裏面是橋接模式的使用方式
package cc.xuepeng; /** 輸出: A系列開門協議解析。 奔馳-A100開門 A系列開門協議解析。 奔馳-A200開門 A系列開門協議解析。 奔馳-A100: 第1個門-開門。 奔馳-A100: 第2個門-開門。 奔馳-A100: 第3個門-開門。 奔馳-A100: 第4個門-開門。 */ public class Client { public static void main(String[] args) { BenzA benzA100 = new BenzA100(new ProtocolBenzA(), "奔馳-A100"); BenzA benzA200 = new BenzA200(new ProtocolBenzA(), "奔馳-A200"); benzA100.openDoor(); benzA200.openDoor(); ((BenzA100) benzA100).openAllDoor(); } }
具體代碼
// A系列奔馳車,類的功能結構層次的父類 public class BenzA { protected Protocol protocol; protected String name; // 在構造函數中,將協議對象注入進來,這裏就是所謂的橋,經過這個protocol對象,能夠調用到協議的方法 public BenzA(Protocol protocol, String name) { this.protocol = protocol; this.name = name; } // 開車門時,先調用協議對象完成業務操做。 public void openDoor() { protocol.resolveOpenDoorProtocol(); System.out.println(name + "開門"); } } public class BenzA100 extends BenzA { public BenzA100(Protocol protocol, String name) { super(protocol, name); } // 若是有特定的方法,能夠從功能結構層側一側直接擴展。 public void openAllDoor() { super.protocol.resolveOpenDoorProtocol(); for (int i = 1; i <= 4; i++) { System.out.println(super.name + ": 第" + i + "個門-開門。"); } } } public class BenzA200 extends BenzA { public BenzA200(Protocol protocol, String name) { super(protocol, name); } } // A系列車的協議解析類,類的實現層次結構的父類 public abstract class Protocol { public abstract void resolveOpenDoorProtocol(); } public class ProtocolBenzA extends Protocol { public void resolveOpenDoorProtocol() { System.out.println("A系列開門協議解析。"); } }
橋接模式,從代碼編寫的角度來看,就是把一個類結構拆分紅了兩個類結構,一邊負責經過類的繼承特定添加功能。另外一邊編寫這些功能的具體實現。而後經過成員變量將實現傳給功能。這樣在擴展功能時,實現側不須要修改,變動實現時,功能側不須要修改。
從設計角度來看,要求咱們設計時先從業務維度出發去思考,考慮後續需求變動是否會使類的結構變得更復雜。
若是業務複雜(類型的子類較多,實現功能也各有不一樣),而且後續的變動或者新功能會很頻繁,那麼就考慮使用橋接模式,將類的功能層次與類的實現層次拆分開,而後以包含(Has a)的方式創建功能層次與實現層側的關係,便可在後續有需求變動時獲得如下幾點好處:
以上就是我對橋接模式的一些理解,有不足之處請你們矯正,謝謝。