橋接模式

在正式介紹之前,先看看下面這個列子。兩種常見文具的區別,它們是毛筆和蠟筆。假如 我們需要大中小3種型號的畫筆,能夠繪製12種不同的顏色,如果使用蠟筆,需要準備3×12 = 36支,但如果使用毛筆的話,只需要提供3種型號的毛筆,外加12個顏料盒即可,涉及到的對 象個數僅爲 3 + 12 = 15,遠小於36,卻能實現與36支蠟筆同樣的功能。如果增加一種新型號的畫筆,並且也需要具有12種顏色,對應的蠟筆需增加12支,而毛筆只需增加一支。爲什麼會這樣呢?通過分析我們可以得知:在蠟筆中,顏色和型號兩個不同的變化維度(即兩個不同 的變化原因)融合在一起,無論是對顏色進行擴展還是對型號進行擴展都勢必會影響另一個維度;但在毛筆中,顏色和型號實現了分離,增加新的顏色或者型號對另一方都沒有任何影響。如果使用軟件工程中的術語,我們可以認爲在蠟筆中顏色和型號之間存在較強的耦合性,而毛筆很好地將二者解耦,使用起來非常靈活,擴展也更爲方便。在軟件開發中,我們也提供了一種設計模式來處理與畫筆類似的具有多變化維度的情況,即本章將要介紹的橋接模式。

概述:

橋接模式是一種很實用的結構型設計模式,如果軟件系統中某個類存在兩個獨立變化的維度,通過該模式可以將這兩個維度分離出來,使兩者可以獨立擴展,讓系統更加符合“單一職責原則”。與多層繼承方案不同,它將兩個獨立變化的維度設計爲兩個獨立的繼承等級結構, 並且在抽象層建立一個抽象關聯,該關聯關係類似一條連接兩個獨立繼承結構的橋,故名橋接模式。

橋接模式用一種巧妙的方式處理多層繼承存在的問題,用抽象關聯取代了傳統的多層繼承, 將類之間的靜態繼承關係轉換爲動態的對象組合關係,使得系統更加靈活,並易於擴展,同 時有效控制了系統中類的個數。橋接定義如下:

定義:

橋接模式(Bridge Pattern): 將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是 一種對象結構型模式,又稱爲柄體 (Handle and Body) 模式或接口 (Interface) 模式。

結構圖:

橋接模式的結構與其名稱一樣,存在一條連接兩個繼承等級結構的橋,如圖所示:
在這裏插入圖片描述
在橋接模式結構圖中包含如下幾個角色:

  • Abstraction(抽象類):用於定義抽象類的接口,它一般是抽象類而不是接口,其中定義了 一個Implementor(實現類接口)類型的對象並可以維護該對象,它與Implementor之間具有關 聯關係,它既可以包含抽象業務方法,也可以包含具體業務方法。
  • RefinedAbstraction(擴充抽象類):擴充由Abstraction定義的接口,通常情況下它不再是抽象類而是具體類,它實現了在Abstraction中聲明的抽象業務方法,在RefinedAbstraction中可以 調用在Implementor中定義的業務方法。
  • Implementor(實現類接口):定義實現類的接口,這個接口不一定要與Abstraction的接口完 全一致,事實上這兩個接口可以完全不同,一般而言,Implementor接口僅提供基本操作,而Abstraction定義的接口可能會做更多更復雜的操作。Implementor接口對這些基本操作進行了聲 明,而具體實現交給其子類。通過關聯關係,在Abstraction中不僅擁有自己的方法,還可以調 用到Implementor中定義的方法,使用關聯關係來替代繼承關係。
  • ConcreteImplementor(具體實現類):具體實現Implementor接口,在不同的 ConcreteImplementor中提供基本操作的不同實現,在程序運行時,ConcreteImplementor對象將 替換其父類對象,提供給抽象類具體的業務操作方法。

橋接模式是一個非常有用的模式,在橋接模式中體現了很多面向對象設計原則的思想,包 括“單一職責原則”、“開閉原則”、“合成複用原則”、“里氏代換原則”、“依賴倒轉原則”等。熟悉橋接模式有助於我們深入理解這些設計原則,也有助於我們形成正確的設計思想和培養良 好的設計風格。

在使用橋接模式時,我們首先應該識別出一個類所具有的兩個獨立變化的維度,將它們設計爲兩個獨立的繼承等級結構,爲兩個維度都提供抽象層,並建立抽象耦合。通常情況下,我們將具有兩個獨立變化維度的類的一些普通業務方法和與之關係最密切的維度設計爲“抽象類”層次結構(抽象部分),而將另一個維度設計爲“實現類”層次結構(實現部分)。例如: 對於毛筆而言,由於型號是其固有的維度,因此可以設計一個抽象的毛筆類,在該類中聲明並部分實現毛筆的業務方法,而將各種型號的毛筆作爲其子類;顏色是毛筆的另一個維度, 由於它與毛筆之間存在一種“設置”的關係,因此我們可以提供一個抽象的顏色接口,而將具體的顏色作爲實現該接口的子類。在此,型號可認爲是毛筆的抽象部分,而顏色是毛筆的實現部分,結構示意圖如圖:

在這裏插入圖片描述

示例代碼:

畫筆類型抽象類:

public abstract class PenType {
    //定義實現類接口對象.
    protected PenColor penColor;

    public void setPenColor(PenColor penColor) {
        this.penColor = penColor;
    }

    //聲名抽象業務方法.
    public abstract void drawing();
}

大號畫筆實現類

public class LargePen extends PenType {
    @Override
    public void drawing() {
    	//調用實現類方法
        penColor.operation();
        System.out.println(" 大號畫筆");
    }
}

小號畫筆實現類

public class SmallPen extends PenType {
    @Override
    public void drawing() {
    	//調用實現類方法
        penColor.operation();
        System.out.println(" 小號畫筆");
    }
}

畫筆顏色接口:

public interface PenColor {
    void operation();
}

紅色畫筆實現類

public class RedPen implements PenColor {
    @Override
    public void operation() {
        System.out.println("紅色");
    }
}

藍色畫筆實現類

public class BulePen implements PenColor {
    @Override
    public void operation() {
        System.out.println("藍色");
    }
}

測試代碼:

@Test
    public void testBridge() {
        PenColor penColor = new GreenPen();
        PenType pen = new LargePen();

        pen.setPenColor(penColor);
        pen.drawing();
    }

如果需要新增一個畫筆類型只需要新增一個 PenType 的實現類即可,同理,如果需要新增一種畫筆顏色,只需要新增一個 PenColor 實現類即可,非常方便,系統具有較好的可擴展性,完全符合 ‘開閉原則’。

總結:

主要優點:
  1. 分離抽象接口及其實現部分。橋接模式使用“對象間的關聯關係”解耦了抽象和實現之間固有的綁定關係,使得抽象和實現可以沿着各自的維度來變化。所謂抽象和實現沿着各自維度的變化,也就是說抽象和實現不再在同一個繼承層次結構中,而是“子類化”它們,使它們各自都具有自己的子類,以便任何組合子類,從而獲得多維度組合對象。
  2. 在很多情況下,橋接模式可以取代多層繼承方案,多層繼承方案違背了“單一職責原則”, 複用性較差,且類的個數非常多,橋接模式是比多層繼承方案更好的解決方法,它極大減少了子類的個數。
  3. 橋接模式提高了系統的可擴展性,在兩個變化維度中任意擴展一個維度,都不需要修改原有系統,符合“開閉原則”。
主要缺點:
  1. 橋接模式的使用會增加系統的理解與設計難度,由於關聯關係建立在抽象層,要求開發者 一開始就針對抽象層進行設計與編程。
  2. 橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用範圍具有一定的侷限 性,如何正確識別兩個獨立維度也需要一定的經驗積累。
適用場景:
  1. 如果一個系統需要在抽象化和具體化之間增加更多的靈活性,避免在兩個層次之間建立靜 態的繼承關係,通過橋接模式可以使它們在抽象層建立一個關聯關係。
  2. “抽象部分”和“實現部分”可以以繼承的方式獨立擴展而互不影響,在程序運行時可以動態 將一個抽象化子類的對象和一個實現化子類的對象進行組合,即系統需要對抽象化角色和實 現化角色進行動態耦合。
  3. 一個類存在兩個(或多個)獨立變化的維度,且這兩個(或多個)維度都需要獨立進行擴展。
  4. 對於那些不希望使用繼承或因爲多層繼承導致系統類的個數急劇增加的系統,橋接模式尤爲適用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章