定義:
將抽象部分與它的實現部分分離,使它們都可以獨立地變化
結構:(書中圖,侵刪)
一個抽象類,用於聚合實現
若干個實現抽象類的類
一個實現的父類
若干個實現了父類的具體實現類
例項:
我想到了一個工作中的例子,通常我們需要去對接一些第三方平臺。
假如最開始你需要對接淘寶平臺,去建立銷售單。然後過段時間又需要去對接京東平臺,也是要建立銷售單。
你的類結構大概是這樣的:
出於物件導向考慮,你可能會給平臺加個父類,變成這樣:
這時候又告訴你,你需要給兩個平臺都新增獲取訂單的功能,然後變成這樣:
假設接下來又要給每個平臺新增建立退貨單,抓取退貨單,然後又新加了兩個平臺,amazon,ebay什麼的。
那簡直就是災難。程式碼沒法複用,複製貼上可不算複用,雖然每個平臺都會有些不一樣,但是功能本身是大同小異的。
於是呢,就引出了我們的橋接模式,按照我的理解來說,就是將系統按照各個維度拆分出來,每個維度都是獨立的部分,互不影響,同時通過一座橋(這裡指聚合,後面會細講)把他們連線起來。
修改之後的類結構是這樣:
操作父類:
package designpattern.bridge; public abstract class Operation { public abstract void operate(); }
建立訂單類:
package designpattern.bridge; public class CreateOrder extends Operation { @Override public void operate() { System.out.println("建立訂單"); } }
獲取訂單類:
package designpattern.bridge; public class GetOrders extends Operation { @Override public void operate() { System.out.println("獲取訂單"); } }
平臺父類(聚合類):
package designpattern.bridge; public abstract class Platform { protected Operation operation; public void setOperation(Operation operation) { this.operation = operation; } public abstract void operate(); }
淘寶類:
package designpattern.bridge; public class Taobao extends Platform { @Override public void operate() { System.out.print("淘寶->"); operation.operate(); } }
京東類:
package designpattern.bridge; public class JingDong extends Platform { @Override public void operate() { System.out.print("京東->"); operation.operate(); } }
客戶端:
package designpattern.bridge; public class Client { public static void main(String[] args) { Operation createOrder=new CreateOrder(); Operation getOrder=new GetOrders(); Platform tb=new Taobao(); tb.setOperation(createOrder); tb.operate(); tb.setOperation(getOrder); tb.operate(); System.out.println("=============================="); Platform jd=new JingDong(); jd.setOperation(createOrder); jd.operate(); jd.setOperation(getOrder); jd.operate(); } }
結果輸出:
淘寶->建立訂單 淘寶->獲取訂單 ============================== 京東->建立訂單 京東->獲取訂單
番外:
書中還提到一個原則:
然後在《effective java》這本書也看到了類似的內容,角度又有些不同:
大概說的是,子類必須依附於父類,如果父類修改了,子類必須得跟著一起改。甚至父類新增了一個和子類簽名相同,但是返回型別不同的方法,會導致你的編譯不通過。
解決方法,就是複合,也是上面說的合成-》新類不繼承父類,而是包含一個擁有父類(雖然沒有繼承,為了前後統一,還是稱之為父類)例項的域,通過這個例項去訪問父類的方法。
上文提到的包裝類是指的裝飾模式(decorator),這裡就不展開了,感興趣的可以看看之前寫的文章:設計模式 | 裝飾模式(decorator)
總結:
核心還是解耦,以及開放-封閉原則。要想方設法的讓新增功能的時候不影響之前的程式碼。設計模式只是表現形式不一樣,核心都差不多。
橋接模式在系統出現多維度的時候就可以考慮使用,其實這種是在最開始就能預見到的,比如文中舉的例子,通常都能想到未來可能增加功能和平臺,所以在寫第一個平臺的第一個功能的時候就應該有意識的去設計。
最後就是在使用繼承前要再三的確認是不是“is a”關係,即便是也不要輕易的使用繼承,複合往往是更優先的選擇。