目錄
摘要
定義
類圖
角色
具體實現
優缺點
優點
缺點
使用場景
使用案例
JDBC 和橋接模式
總結
摘要
????????在軟件開發領域,隨著系統規模和復雜性的不斷攀升,如何設計出具有良好擴展性、靈活性以及可維護性的軟件架構成為關鍵挑戰。橋接模式作為一種重要的結構型設計模式,為解決這些問題提供了有效的方案。它通過巧妙的設計,將抽象部分與實現部分進行分離,使二者能夠獨立發展變化,極大地提升了軟件系統應對變化的能力。
定義
????????將抽象部分與它的實現部分分離,使它們都可以獨立地變化。在許多傳統設計中,抽象與實現緊密耦合,一旦其中一方發生改變,往往會對另一方產生較大影響,這無疑增加了系統的維護成本和復雜性。橋接模式則打破了這種束縛,通過聚合關系代替繼承關系,實現了抽象化和實現化部分的解耦。?
????????例如,在一個圖形繪制系統中,假設我們有不同類型的圖形(如圓形、矩形等),同時需要在不同的平臺(如 Windows、Mac 等)上進行繪制。若采用傳統的繼承方式,每一種圖形類型都需要為每個平臺創建一個子類,這樣會導致類的數量呈指數級增長,代碼的維護和擴展變得極為困難。而橋接模式可以將圖形的抽象(如 Shape 類)與具體的繪制實現(如 WindowsDrawingAPI、MacDrawingAPI 等實現類)分離,通過聚合關系將它們關聯起來,使得圖形類型和繪制平臺能夠獨立發展,大大簡化了系統的設計。
類圖
角色
-
Abstraction(抽象類):處于整個結構的上層,用于定義抽象的接口。它一般是抽象類而非接口,其中定義了一個 Implementor(實現類接口)類型的對象并維護該對象,通過這種方式與 Implementor 建立關聯關系。抽象類中聲明的方法往往依賴于 Implementor 中定義的操作來實現具體功能。?
-
RefinedAbstraction(提煉抽象類):對 Abstraction 定義的接口進行擴充。通常情況下,它不再是抽象類而是具體類,實現了在 Abstraction 中聲明的抽象業務方法。在其實現過程中,會調用在 Implementor 中定義的業務方法,從而將抽象與實現進行結合。?
-
Implementor(實現類接口):該接口定義了實現類的基本操作規范。需要注意的是,它的接口設計不一定要與 Abstraction 的接口完全一致,事實上二者可能差異較大。Implementor 接口主要聚焦于提供一些基礎的、底層的操作,這些操作的具體實現由其子類負責。通過這種抽象接口的定義,為不同的具體實現提供了統一的規范。?
-
ConcreteImplementor(具體實現類):具體實現 Implementor 接口的類,針對不同的業務需求和場景,在各個 ConcreteImplementor 中提供基本操作的不同實現。在程序運行過程中,ConcreteImplementor 對象會替換其父類對象,為抽象類提供具體的業務操作方法,實現實際的功能。
具體實現
-
Abstraction(抽象類):作為抽象層的代表,它為整個系統提供了一個高層次的抽象接口。以圖形繪制系統為例,抽象類 Shape 可以定義一些通用的圖形操作方法,如繪制(draw)、縮放(resize)等,但并不涉及具體的繪制邏輯。它持有一個實現類接口 IDrawingAPI 類型的對象,通過該對象來調用具體的繪制實現。
public abstract class Shape {?protected IDrawingAPI drawingAPI;?public Shape(IDrawingAPI drawingAPI) {?this.drawingAPI = drawingAPI;?}?public abstract void draw();?public abstract void resize(double factor);?
}
-
RefinedAbstraction(提煉抽象類):以 Circle 類為例,它繼承自 Shape 抽象類,是提煉抽象類的具體體現。在 Circle 類中,實現了 Shape 類中定義的 draw 和 resize 方法,并借助 drawingAPI 對象調用具體的繪制實現。
public class Circle extends Shape {?private double x, y, radius;?public Circle(double x, double y, double radius, IDrawingAPI drawingAPI) {?super(drawingAPI);?this.x = x;?this.y = y;?this.radius = radius;?}?@Override?public void draw() {?drawingAPI.drawCircle(x, y, radius);?}?@Override?public void resize(double factor) {?radius *= factor;?}?
}
-
Implementor(實現類接口):定義了具體實現類需要遵循的接口規范。在圖形繪制系統中,IDrawingAPI 接口定義了繪制圓形、矩形等圖形的方法。
public interface IDrawingAPI {?void drawCircle(double x, double y, double radius);?void drawRectangle(double x1, double y1, double x2, double y2);?
}
-
ConcreteImplementor(具體實現類):如 WindowsAPI 和 MacAPI 類,分別實現了 IDrawingAPI 接口,提供了在 Windows 和 Mac 平臺上的具體繪制實現。
public class WindowsAPI implements IDrawingAPI {?@Override?public void drawCircle(double x, double y, double radius) {?System.out.println("在Windows平臺繪制圓形,圓心:(" + x + ", " + y + "),半徑:" + radius);?}?@Override?public void drawRectangle(double x1, double y1, double x2, double y2) {?System.out.println("在Windows平臺繪制矩形,左上角:(" + x1 + ", " + y1 + "),右下角:(" + x2 + ", " + y2 + ")");?}?
}?
public class MacAPI implements IDrawingAPI {?@Override?public void drawCircle(double x, double y, double radius) {?System.out.println("在Mac平臺繪制圓形,圓心:(" + x + ", " + y + "),半徑:" + radius);?}?@Override?public void drawRectangle(double x1, double y1, double x2, double y2) {?System.out.println("在Mac平臺繪制矩形,左上角:(" + x1 + ", " + y1 + "),右下角:(" + x2 + ", " + y2 + ")");?}?
}
優缺點
優點
-
實現抽象和實現的分離:這是橋接模式的核心優勢。通過將抽象部分與實現部分解耦,使得它們能夠獨立地進行演化。例如,在圖形繪制系統中,圖形類型的擴展(如新增三角形、菱形等圖形)不會影響到繪制平臺的實現,反之,繪制平臺的更新(如支持新的操作系統)也不會對圖形類型造成影響,大大提高了系統的靈活性和可維護性。?
-
提高系統的可擴充性:在橋接模式下,兩個變化維度(抽象和實現)中的任意一個進行拓展,都無需對原有系統進行大規模修改。以消息發送系統為例,若要新增一種消息類型(如推送消息),只需在抽象部分添加相應的類,并在實現部分關聯已有的消息發送方式(如郵件、短信等);若要新增一種消息發送方式(如即時通訊工具),也只需在實現部分添加具體實現類,然后在需要使用的抽象類中進行關聯即可,符合開閉原則。?
-
避免多層繼承的弊端:多層繼承方案容易違背類的單一職責原則,導致代碼復用性差,并且類的數量會隨著繼承層次的增加而迅速膨脹,使得系統變得復雜難以維護。橋接模式采用聚合關系替代繼承關系,有效避免了這些問題,使得系統結構更加簡潔清晰。
缺點
-
增加系統的理解與設計難度:由于橋接模式中的聚合關聯關系建立在抽象層,這要求開發者在設計和編程時,需要從更高的抽象層次去思考和規劃,對開發者的抽象思維能力和設計經驗有較高要求。初學者可能較難理解和掌握這種設計方式,增加了學習和上手的難度。?
-
使用范圍具有一定的局限性:橋接模式的應用依賴于正確識別出系統中兩個獨立變化的維度。然而,在一些復雜系統中,準確判斷和分離這兩個維度并非易事。如果對系統的分析不準確,強行使用橋接模式,可能不僅無法發揮其優勢,反而會使系統變得更加復雜混亂,因此其使用場景受到一定限制。
使用場景
-
一個類存在兩個獨立變化的維度,且這兩個維度都需要進行拓展:例如在電商系統中,商品有不同的類別(如電子產品、服裝、食品等),同時有不同的促銷策略(如打折、滿減、贈品等)。類別和促銷策略這兩個維度相互獨立且都可能不斷擴展,使用橋接模式可以將商品類別抽象與促銷策略實現進行分離,方便系統根據業務發展進行功能擴展。?
-
如果一個系統需要在構建的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承關系:以跨平臺的游戲開發為例,游戲中的角色具有各種行為(如移動、攻擊、防御等抽象行為),而這些行為在不同的游戲平臺(如 PC、手機、主機等)上有不同的實現方式。通過橋接模式,可以將角色行為的抽象與平臺相關的實現解耦,使游戲在不同平臺上的移植和擴展更加容易,提高了系統的靈活性。?
-
對于那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統:如在圖形編輯軟件中,圖形元素有多種類型(矩形、圓形、多邊形等),并且需要支持不同的顯示模式(普通模式、高清模式、3D 模式等)。若采用繼承方式,會產生大量的子類(每種圖形類型對應每種顯示模式都需要一個子類)。使用橋接模式,將圖形類型抽象與顯示模式實現分離,可以有效避免類的數量爆炸,簡化系統設計。
使用案例
JDBC 和橋接模式
????????JDBC(Java Database Connectivity)是 Java 語言中用于連接和操作數據庫的標準 API,它很好地體現了橋接模式的應用。在 JDBC 中,抽象部分是 Java.sql 包中定義的一系列接口,如 Connection、Statement、ResultSet 等,這些接口定義了與數據庫交互的抽象操作,如建立連接、執行 SQL 語句、獲取查詢結果等。而實現部分則是各個數據庫廠商提供的數據庫驅動,如 MySQL 的驅動、Oracle 的驅動等。不同的數據庫驅動實現了 Java.sql 包中的接口,提供了針對各自數據庫的具體操作實現。?
????????通過這種方式,Java 程序在使用 JDBC 操作數據庫時,無需關心具體使用的是哪種數據庫以及其底層實現細節,只需要通過抽象接口進行操作。當需要更換數據庫時,只需要更換對應的數據庫驅動(實現部分),而 Java 程序中使用 JDBC 接口的代碼(抽象部分)無需修改,極大地提高了代碼的可移植性和可維護性,充分發揮了橋接模式將抽象與實現分離的優勢。?
總結
????????橋接模式作為一種強大的結構型設計模式,通過獨特的設計理念和結構,有效地解決了軟件系統中抽象與實現耦合的問題,為構建靈活、可擴展的軟件架構提供了有力的支持。雖然它存在一定的應用門檻和局限性,但在合適的場景下應用,能夠顯著提升軟件系統的質量和開發效率,是開發者在軟件設計過程中不可或缺的重要工具。