【設計模式】第七篇:和我一起簡單認識橋接模式

BWH_Steven發表於2020-11-23

一 引言

橋接模式理解起來也是非常簡單,我們仍然從生活中的問題出發,如果一些事物的分類可以從兩個或者多個維度來劃分,就比如不同品牌和不同排量的汽車,他們可以有 M x N 種結果(例如:奧迪A8 2.0排量,奧迪A6 2.0排量,賓士S350L 3.0排量,等等)

這種情況下如果選擇繼承的方式,就會出現一種多層繼承的關係,子類就會非常多,同時擴充套件也很麻煩

像這樣的例子還有很多,比如品牌和產品型別之間,或者不同顏色和字型的圖形或者文字,等等

二 橋接模式引入

還是老規矩,直接用實際的程式碼例子引入

背景:相機品牌(索尼,佳能等)和相機型別(單反,微單,卡片機等)兩種維族的組合結果

我們想要做的就是取消他們的繼承關係,而使用組合

  • 先建立一個抽象的相機品牌類
/**
 * 相機品牌類
 */
public interface CameraBrand {
    void showInfo();
}
  • 接著就是兩個具體的實現類,這裡舉了索尼和佳能兩個品牌
/**
 * 索尼品牌
 */
public class Sony implements CameraBrand {
    @Override
    public void showInfo() {
        System.out.print("【索尼】");
    }
}
/**
 * 佳能品牌
 */
public class Canon implements CameraBrand {
    @Override
    public void showInfo() {
        System.out.print("【佳能】");
    }
}
  • 下面再將相機產品類抽象出來,為了實現組合,引入相機品牌成員,為了能讓在子類中也能訪問到,我用了 protected
/**
 * 抽象相機類
 */
public abstract class Camera {
    // 將品牌組合進來
    protected CameraBrand cameraBrand;

    public Camera(CameraBrand cameraBrand) {
        this.cameraBrand = cameraBrand;
    }

    public void showInfo(){
        cameraBrand.showInfo();
    }
}
  • 下面就是兩個相機的產品具體型別
/**
 * 單反相機
 */
public class SlrCameras extends Camera {

    public SlrCameras(CameraBrand cameraBrand) {
        super(cameraBrand);
    }

    @Override
    public void showInfo() {
        super.showInfo();
        System.out.println("單反相機");
    }
}
/**
 * 卡片相機(數字相機)
 */
public class DigitalCamera extends Camera {

    public DigitalCamera(CameraBrand cameraBrand) {
        super(cameraBrand);
    }

    @Override
    public void showInfo() {
        super.showInfo();
        System.out.println("卡片相機(數字相機)");
    }
}

測試一下

public class Test {
    public static void main(String[] args) {
        // 索尼單反相機
        Camera camera = new SlrCameras(new Sony());
        camera.showInfo();
        // 佳能卡片相機
        Camera camera2 = new DigitalCamera(new Canon());
        camera2.showInfo();
    }
}

執行結果:

【索尼】單反相機
【佳能】卡片相機(數字相機)

從上述程式碼中可以看出,我們現在已經可以對不同型別和不同產品的相機進行任意的組合了,例如索尼單反相機,或者佳能單反相機都是可以的,如果想要增加一個品牌或者產品只需要增加具體的實現類就可以了

三 橋接模式理論

(一) 定義和特點

定義:將抽象與實現分離,使它們可以獨立變化

實現的意思並不是指抽象的派生類,而是指通過組合來代替繼承關係,從而降低抽象和具體實現產品兩個可變換維度之間的耦合,就像我們的相機品牌和相機產品型別之間的分離

(二) 結構

簡單說明一下其中的角色

  • 實現化角色(Implementor):定義實現化角色的介面,供擴充套件抽象化角色使用

    • 例如抽象出相機的品牌,可以擴充套件出例如佳能索尼等各種品牌
  • 具體實現化角色(ConcreteImplementor):實現化角色的具體實現

    • 例如各種品牌
  • 抽象化(Abstraction)角色:定義一個抽象類,其中引用了實現化角色(想要組合)

    • 例如相機產品
  • 擴充套件抽象化(RefinedAbstraction)角色:抽象化角色子類,實現父類方法,且通過組合關係呼叫實現化角色中的業務方法

    • 例如具體相機產品,單反相機,卡片相機等等

( 三) 優點和缺點

優點:

經常遇到一些可以通過兩個或多個維度劃分的事物,第一種解決方式就是多層繼承,但是複用性比較差,同時類的個數也會很多,橋接模式是改進其的更好辦法

橋接模式增強了系統的擴充套件性,在兩個維度中擴充套件任意一個維度都不需要修改原有程式碼,符合開閉原則

缺點:

橋接模式增加了系統的理解與設計難度:因為聚合關係建立在抽象層,要求開發者針對抽象化進行設計與程式設計,能正確地識別出系統中兩個獨立變化的維度

(四) 使用場景

  • 一個系統需要在構建的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯絡,通過橋接模式可以使它們在抽象層建立一個關聯關係。

    • 抽象化角色和實現化角色可以以繼承的方式獨立擴充套件而互不影響,在程式執行時可以動態將一個抽象化子類的物件和一個實現化子類的物件進行組合,即系統需要對抽象化角色和實現化角色進行動態耦合
  • 一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴充套件

  • 雖然在系統中使用繼承是沒有問題的,但是由於抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者

  • 不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統

相關文章