1. 程式人生 > >設計模式:橋接模式及程式碼示例、橋接模式在jdbc中的體現、注意事項

設計模式:橋接模式及程式碼示例、橋接模式在jdbc中的體現、注意事項


# 0、背景
加入一個手機分為多種款式,不同款式分為不同品牌。這些詳細分類下分別進行操作。 如果傳統做法,需要將手機,分為不同的子類,再繼續分,基本屬於一個龐大的多叉樹,然後每個葉子節點進行相同名稱、但是細節不同的功能實現。
**問題**: 1. **類爆炸**:類的增加基本沒有任何優化,多一個就要妥妥的增加類; 2. **違反單一原則**:增加一個品牌,影響每種型別下的這個品牌,增加一個型別,影響每個品牌的這個型別。
# 一、橋接模式
解決上面說的問題的方式就是使用橋接模式。 **橋接(Bridge)模式是指,將實現和抽象放在兩個不同的類層次中,使得兩個層次可以獨立改變。** 橋接模式是一種**結構型設計模式**,基於類的最小設計原則,讓不同的類承擔不同的職責。(單一原則) 橋接模式的主要特點是,把抽象 Abstraction 和行為實現 Implementation 分離開,從而保持各部分的獨立和應對他們的功能擴充套件。 類圖如下所示:
其中,承擔 **橋接功能** 的抽象類就是 Abstraction。 看起來還是很抽象,結合上面的手機問題,畫出對應的類圖,再結合來看:
也就是說,比起原來的樹狀結構,用橋接模式,將行為實現放在一邊,有自己的介面;將抽象出的另一個維度放在一邊,有自己的抽象父類和子類,然後將上層的抽象類和實現介面相關聯。 這樣的話,前面遇到的問題: - 新增手機樣式,就在左邊新增抽象類定義就可以; - 新增品牌,在右邊新增實現類就可以。 - 其他部分都不會被影響。 觀察上面的圖,橋接的意味也很明顯,當 QuanPingPhone 使用一個 call 方法的時候,繼承的其實是父類的方法,而這裡面組合了另一個性質,比如是 Oppo 手機的 call 方法,那麼就是通過橋接一路引過去的。 (忽略我的英語) 按照這個思路我們來寫一個實現: ```java /* 品牌,介面 */ public interface Brand { void open(); void close(); void call(); } ``` ```java public class Xiaomi implements Brand{ @Override public void open() { System.out.println("小米手機開機"); } @Override public void close() { System.out.println("小米手機關機"); } @Override public void call() { System.out.println("小米手機打電話"); } } ``` ```java public class Vivo implements Brand{ @Override public void open() { System.out.println("vivo手機開機"); } @Override public void close() { System.out.println("vivo手機關機"); } @Override public void call() { System.out.println("vivo手機打電話"); } } ``` ```java /* 抽象層:手機,通過品牌介面聚合不同品牌 */ public abstract class Phone { //品牌 private Brand brand; public Phone(Brand brand) { this.brand = brand; } protected void open(){ this.brand.open(); } protected void close(){ this.brand.close(); } protected void call(){ this.brand.call(); } } ``` ```java /* 摺疊手機,繼承抽象類手機 */ public class BoldPhone extends Phone{ //構造器 public BoldPhone(Brand brand) { super(brand); } public void open(){ super.open();//實際上通過父類的open,橋接到了brand下面的某個子類的open System.out.println("開啟的是摺疊手機"); } public void close(){ super.close(); System.out.println("關閉的是摺疊手機"); } public void call(){ super.call(); System.out.println("打電話的的是摺疊手機"); } } ``` ```java /* 全面屏手機,繼承抽象類手機 */ public class ScreenPhone extends Phone{ public ScreenPhone(Brand brand) { super(brand); } public void open(){ super.open();//實際上通過父類的open,橋接到了brand下面的某個子類的open System.out.println("開啟的是全面屏手機"); } public void close(){ super.close(); System.out.println("關閉的是全面屏手機"); } public void call(){ super.call(); System.out.println("打電話的的是全面屏手機"); } } ``` 呼叫試試: ```java /* 客戶端 */ public class Client { public static void main(String[] args) { //獲取一個手機,需要的是樣式+手機兩個實現類 //通過Phone這個抽象類,增加一個樣式為BoldPhone的手機,橋接到品牌為Xiaomi Phone phone = new BoldPhone(new Xiaomi()); phone.open(); phone.call(); phone.close(); } } ``` 這樣的話,如果擴充套件起來,比如新增加一種樣式的手機,我們只需要繼承Phone再寫一個子類,其餘都不需要更改,如果新增加一個品牌的手機,只需要實現Band介面再寫一個實現類,其餘都不需要更改。
# 二、使用橋接模式的原始碼:JDBC
JDBC 原始碼裡: MySQL 的 Connection 介面實現的是 java.sql.Connection 介面,同時 Oracle 資料庫也一樣可以實現 java.sql.Connection 介面,他們向下都可以有更多的實現子類。 然後 DriverManager 相當於橋接模組,依賴和聚合 java.sql.Connection 介面,供客戶端呼叫。 和我們上面所說的略微不同,就是 DriverManager 不是抽象類,而是直接的具體實現。
# 三、橋接模式的注意事項
1. 橋接模式實現了抽象和實現部分的分離,提高了系統的靈活性,讓抽象部分和實現部分獨立開來,有助於系統的分層設計。 2. 高層只需要知道抽象部分和實現部分的介面,而不需要知道其他具體實現; 3. 替代了多層繼承,大大減少了子類的數量; 4. 橋接模式的引入,增加了系統的設計和理解難度,由於聚合關聯關係建立在抽象層,要求開發者針能對抽象層進行設計和程式設計; 5. 適用範圍有侷限性 **應用場景:** 1. jdbc:多種驅動,多種資料庫; 2. 銀行轉賬:因為轉賬動作要分很多類,使用者也分很多類,所以他們之間不適合多層繼承; 3. 訊息管理:訊息型別不同,訊息傳送方式