## 引入
在閻宏博士的《JAVA與模式》一書中開頭是這樣描述橋梁(Bridge)模式的:
> 橋梁模式是對象的結構模式。又稱為柄體(Handle and Body)模式或接口(Interface)模式。橋梁模式的用意是“將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化”。
## 定義
橋接模式即將抽象部分與它的實現部分分離開來,使他們都可以獨立變化。
橋接模式將繼承關系轉化成關聯關系,它降低了類與類之間的耦合度,減少了系統中類的數量,也減少了代碼量。
橋梁模式雖然不是一個使用頻率很高的模式,但是熟悉這個模式對于理解面向對象的設計原則,包括“開-閉”原則以及組合/聚合復用原則都很有幫助。理解好這兩個原則,有助于形成正確的設計思想和培養良好的設計風格。
橋梁模式的用意是“**將抽象化(Abstraction)與實現化(Implementation)脫耦,使得二者可以獨立地變化**”。這句話很短,但是第一次讀到這句話的人很可能都會思考良久而不解其意。
這句話有三個關鍵詞,也就是抽象化、實現化和脫耦。理解這三個詞所代表的概念是理解橋梁模式用意的關鍵。
**抽象化**
從眾多的事物中抽取出共同的、本質性的特征,而舍棄其非本質的特征,就是抽象化。例如蘋果、香蕉、生梨、 桃子等,它們共同的特性就是水果。得出水果概念的過程,就是一個抽象化的過程。要抽象,就必須進行比較,沒有比較就無法找到在本質上共同的部分。共同特征是指那些能把一類事物與他類事物區分開來的特征,這些具有區分作用的特征又稱本質特征。因此抽取事物的共同特征就是抽取事物的本質特征,舍棄非本質的特征。 所以抽象化的過程也是一個裁剪的過程。在抽象時,同與不同,決定于從什么角度上來抽象。抽象的角度取決于分析問題的目的。
通常情況下,一組對象如果具有相同的特征,那么它們就可以通過一個共同的類來描述。如果一些類具有相同的特征,往往可以通過一個共同的抽象類來描述。
**實現化**
抽象化給出的具體實現,就是實現化。
一個類的實例就是這個類的實例化,一個具體子類是它的抽象超類的實例化。
**脫耦**
所謂耦合,就是兩個實體的行為的某種強關聯。而將它們的強關聯去掉,就是耦合的解脫,或稱脫耦。在這里,脫耦是指將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯。
所謂**強關聯**,就是在編譯時期已經確定的,無法在運行時期動態改變的關聯;所謂**弱關聯**,就是可以動態地確定并且可以在運行時期動態地改變的關聯。顯然,在Java語言中,繼承關系是強關聯,而聚合關系是弱關聯。
將兩個角色之間的繼承關系改為聚合關系,就是將它們之間的強關聯改換成為弱關聯。因此,橋梁模式中的所謂脫耦,就是指在一個軟件系統的抽象化和實現化之間使用聚合關系而不是繼承關系,從而使兩者可以相對獨立地變化。這就是橋梁模式的用意。
## 結構
下圖所示就是一個實現了橋梁模式的示意性系統的結構圖:

可以看出,這個系統含有兩個等級結構:
一、由抽象化角色和修正抽象化角色組成的抽象化等級結構。
二、由實現化角色和兩個具體實現化角色所組成的實現化等級結構。
橋梁模式所涉及的角色有:
● 抽象化(Abstraction)角色:抽象化給出的定義,并保存一個對實現化對象的引用。
● 修正抽象化(RefinedAbstraction)角色:擴展抽象化角色,改變和修正父類對抽象化的定義。
● 實現化(Implementor)角色:這個角色給出實現化角色的接口,但不給出具體的實現。必須指出的是,這個接口不一定和抽象化角色的接口定義相同,實際上,這兩個接口可以非常不一樣。實現化角色應當只給出底層操作,而抽象化角色應當只給出基于底層操作的更高一層的操作。
● 具體實現化(ConcreteImplementor)角色:這個角色給出實現化角色接口的具體實現。
抽象化角色就像是一個水杯的手柄,而實現化角色和具體實現化角色就像是水杯的杯身。手柄控制杯身,這就是此模式別名“柄體”的來源。
對象是對行為的封裝,而行為是由方法實現的。在這個示意性系統里,抽象化等級結構中的類封裝了operation()方法;而實現化等級結構中的類封裝的是operationImpl()方法。當然,在實際的系統中往往會有多于一個的方法。
抽象化等級結構中的方法通過向對應的實現化對象的委派實現自己的功能,這意味著抽象化角色可以通過向不同的實現化對象委派,來達到動態地轉換自己的功能的目的。
## 代碼實現
在開發中可能不止使用一種數據庫, 例如Mysql,SqlServer數據庫等,現在使用橋接模式創建一個連接數據庫的驅動,然后對每一個數據庫提供各自的實現.對于使用某一個數據庫的時候只需要切換一下就行。

數據庫接口
~~~
public interface Driver {
public void connect();
}
~~~
Mysql數據庫實現類
~~~
public class MysqlDriver implements Driver {
@Override
public void connect() {
System.out.println("連接Mysql數據庫");
}
}
~~~
SqlServer數據庫實現類
~~~
public class SqlServerDriver implements Driver {
@Override
public void connect() {
System.out.println("連接SQLServer數據庫");
}
}
~~~
橋梁類(抽象類)
~~~
public abstract class Bridge {
private Driver driver;
public void connect(){
driver.connect();
}
public void setDriver(Driver driverTemp){
this.driver = driverTemp;
}
public Driver getDriver(){
return this.driver;
}
}
~~~
橋梁類(實現類)
~~~
public class MyBridge extends Bridge {
}
~~~
測試類
~~~
public class BridgeTest {
public static void main(String[] args) {
Bridge mysqlBridge = new MyBridge();
Driver mysqlDriver = new MysqlDriver();
mysqlBridge.setDriver(mysqlDriver);
mysqlBridge.connect();
Driver sqlServerDriver = new SqlServerDriver();
mysqlBridge.setDriver(sqlServerDriver);
mysqlBridge.connect();
}
}
~~~
## 橋梁模式在Java中的使用
橋梁模式在Java應用中的一個非常典型的例子就是JDBC驅動器。JDBC為所有的關系型數據庫提供一個通用的界面。一個應用系統動態地選擇一個合適的驅動器,然后通過驅動器向數據庫引擎發出指令。這個過程就是將抽象角色的行為委派給實現角色的過程。
抽象角色可以針對任何數據庫引擎發出查詢指令,因為抽象角色并不直接與數據庫引擎打交道,JDBC驅動器負責這個底層的工作。由于JDBC驅動器的存在,應用系統可以不依賴于數據庫引擎的細節而獨立地演化;同時數據庫引擎也可以獨立于應用系統的細節而獨立的演化。兩個獨立的等級結構如下圖所示,左邊是JDBC API的等級結構,右邊是JDBC驅動器的等級結構。應用程序是建立在JDBC API的基礎之上的。

應用系統作為一個等級結構,與JDBC驅動器這個等級結構是相對獨立的,它們之間沒有靜態的強關聯。應用系統通過委派與JDBC驅動器相互作用,這是一個橋梁模式的例子。
JDBC的這種架構,把抽象部分和具體部分分離開來,從而使得抽象部分和具體部分都可以獨立地擴展。對于應用程序而言,只要選用不同的驅動,就可以讓程序操作不同的數據庫,而無需更改應用程序,從而實現在不同的數據庫上移植;對于驅動程序而言,為數據庫實現不同的驅動程序,并不會影響應用程序。
## 優點
* 1、分離抽象接口及其實現部分。提高了比繼承更好的解決方案。
* 2、橋接模式提高了系統的可擴充性,在兩個變化維度中任意擴展一個維度,都不需要修改原有系統。
* 3、實現細節對客戶透明,可以對用戶隱藏實現細節。
## 缺點
* 1、橋接模式的引入會增加系統的理解與設計難度,由于聚合關聯關系建立在抽象層,要求開發者針對抽象進行設計與編程。
* 2、橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用范圍具有一定的局限性。
## 使用場景
* 1、如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯系,通過橋接模式可以使它們在抽象層建立一個關聯關系。
* 2、對于那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用。
* 3、一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。
## 總結
* 1、橋接模式實現了抽象化與實現化的脫耦。他們兩個互相獨立,不會影響到對方。
* 2、對于兩個獨立變化的維度,使用橋接模式再適合不過了。
* 3、對于“具體的抽象類”所做的改變,是不會影響到客戶。
- java
- 設計模式
- 設計模式總覽
- 設計原則
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 建造者模式
- 原型模式
- 適配器模式
- 裝飾者模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
- 策略模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責任鏈模式
- 命令模式
- 備忘錄模式
- 狀態模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 附錄
- JVM相關
- JVM內存結構
- Java虛擬機的內存組成以及堆內存介紹
- Java堆和棧
- 附錄-數據結構的堆棧和內存分配的堆區棧區的區別
- Java內存之Java 堆
- Java內存之虛擬機和內存區域概述
- Java 內存之方法區和運行時常量池
- Java 內存之直接內存(堆外內存)
- JAVA內存模型
- Java內存模型介紹
- 內存模型如何解決緩存一致性問題
- 深入理解Java內存模型——基礎
- 深入理解Java內存模型——重排序
- 深入理解Java內存模型——順序一致性
- 深入理解Java內存模型——volatile
- 深入理解Java內存模型——鎖
- 深入理解Java內存模型——final
- 深入理解Java內存模型——總結
- 內存可見性
- JAVA對象模型
- JVM內存結構 VS Java內存模型 VS Java對象模型
- Java的對象模型
- Java的對象頭
- HotSpot虛擬機
- HotSpot虛擬機對象探秘
- 深入分析Java的編譯原理
- Java虛擬機的鎖優化技術
- 對象和數組并不是都在堆上分配內存的
- 垃圾回收
- JVM內存管理及垃圾回收
- JVM 垃圾回收器工作原理及使用實例介紹
- JVM內存回收理論與實現(對象存活的判定)
- JVM參數及調優
- CMS GC日志分析
- JVM實用參數(一)JVM類型以及編譯器模式
- JVM實用參數(二)參數分類和即時(JIT)編譯器診斷
- JVM實用參數(三)打印所有XX參數及值
- JVM實用參數(四)內存調優
- JVM實用參數(五)新生代垃圾回收
- JVM實用參數(六) 吞吐量收集器
- JVM實用參數(七)CMS收集器
- JVM實用參數(八)GC日志
- Java性能調優原則
- JVM 優化經驗總結
- 面試題整理
- 面試題1
- java日志規約
- Spring安全
- OAtuth2.0簡介
- Spring Session 簡介(一)
- Spring Session 簡介(二)
- Spring Session 簡介(三)
- Spring Security 簡介(一)
- Spring Security 簡介(二)
- Spring Security 簡介(三)
- Spring Security 簡介(四)
- Spring Security 簡介(五)
- Spring Security Oauth2 (一)
- Spring Security Oauth2 (二)
- Spring Security Oauth2 (三)
- SpringBoot
- Shiro
- Shiro和Spring Security對比
- Shiro簡介
- Session、Cookie和Cache
- Web Socket
- Spring WebFlux