結構型模式-橋接模式(處理多維度變化)

橋接模式是一種很實用的結構型設計模式,若是軟件系統中某個類存在兩個獨立變化的維度,經過該模式能夠將這兩個維度分離出來,使二者能夠獨立擴展,讓系統更加符合「單一職責原則」。與多層繼承方案不一樣,它將兩個獨立變化的維度設計爲兩個獨立的繼承等級結構,而且在抽象層創建一個抽象關聯,該關聯關係相似一條鏈接兩個獨立繼承結構的橋,故名橋接模式。
橋接模式用一種巧妙的方式處理多層繼承存在的問題,用抽象關聯取代了傳統的多層繼承,將類之間的靜態繼承關係轉換爲動態的對象組合關係,使得系統更加靈活,並易於擴展,同時有效控制了系統中類的個數。git

1. 定義

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

2. 結構

橋接模式的結構與其名稱同樣,存在一條鏈接兩個繼承等級結構的橋,橋接模式結構如圖所示:設計模式

橋接模式

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

3. 代碼實現

鉛筆能夠分爲不一樣大小規格的,同時每個規格均可以選擇不一樣的顏色,規則和顏色做爲鉛筆的兩個維度,若是採用多層繼承的結構,每一個鉛筆規格下在提供不一樣顏色的子類,會致使系統中類的個數急劇增長,同時擴展麻煩,無論增長顏色仍是規格都須要增長大量的具體類。所以這邊使用橋接嘛事,將這兩個維度設計爲兩個獨立的繼承等級結構,爲兩個維度都提供抽象層,並創建抽象耦合。ide

一般狀況下,咱們將具備兩個獨立變化維度的類的一些普通業務方法和與之關係最密切的維度設計爲「抽象類」層次結構(抽象部分),而將另外一個維度設計爲「實現類」層次結構(實現部分)。測試

對於鉛筆而言,因爲規格型號是其固有的維度,所以能夠設計一個抽象的鉛筆類,在該類中聲明並部分實現鉛筆的業務方法,而將各類型號的鉛筆做爲其子類;顏色是鉛筆的另外一個維度,因爲它與鉛筆之間存在一種「設置」的關係,所以咱們能夠提供一個抽象的顏色接口,而將具體的顏色做爲實現該接口的子類。代碼以下:this

//輔助類,設置顏色的時候使用該類
public class Image {
    private String line;

    private String color;

    public String getLine() {
        return line;
    }

    public void setLine(String line) {
        this.line = line;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Image{" + "line='" + line + '\'' + ", color='" + color + '\'' + '}';
    }
}

//抽象鉛筆類
public abstract class AbstractPencil {

    protected IColorImp color;

    public void setColorImp(IColorImp color) {
        this.color = color;
    }

    public abstract void draw();

}


//抽象顏色設置實現類:實現類接口
public interface IColorImp {
    void setColor(Image image);
}

//紅色設置實現類:具體實現類
public class RedColorImp implements IColorImp {

    @Override
    public void setColor(Image image) {
        image.setColor("紅色");
    }
}

//綠色設置實現類:具體實現類
public class GreenImpl implements IColorImp {

    @Override
    public void setColor(Image image) {
        image.setColor("綠色");
    }
}

//大號鉛筆:擴充抽象類
public class BigPencil extends AbstractPencil {

    @Override
    public void draw() {
        Image image=new Image();
        image.setLine("大");
        //其餘代碼
        color.setColor(image);
        //其餘代碼
        System.out.println(image);
    }
}

//小號鉛筆:擴充抽象類
public class SmallPencil extends AbstractPencil {

    @Override
    public void draw() {
        Image image=new Image();
        image.setLine("小");
        //其餘代碼
        color.setColor(image);
        //其餘代碼
        System.out.println(image);
    }
}

//測試類
public class Client {

    public static void main(String[] args) {
        AbstractPencil pencil=new BigPencil();
        IColorImp colorImp=new RedColorImp();
        pencil.setColorImp(colorImp);
        pencil.draw();
    }
}

//Image{line='大', color='紅色'}

可以使用配置文件來選定特定型號的鉛筆和顏色,當添加新的鉛筆尺寸型號或者顏色的時候,只需增長一個對應的擴充抽象類或具體實現類便可,系統具備較好的可擴展性,徹底符合「開閉原則」。設計

4. 適配器模式與橋接模式的聯用

在軟件開發中,適配器模式一般能夠與橋接模式聯合使用。適配器模式能夠解決兩個已有接口間不兼容問題,在這種狀況下被適配的類每每是一個黑盒子,有時候咱們不想也不能改變這個被適配的類,也不能控制其擴展。適配器模式一般用於現有系統與第三方產品功能的集成,採用增長適配器的方式將第三方類集成到系統中。橋接模式則不一樣,用戶能夠經過接口繼承或類繼承的方式來對系統進行擴展。3d

橋接模式和適配器模式用於設計的不一樣階段,橋接模式用於系統的初步設計,對於存在兩個獨立變化維度的類能夠將其分爲抽象化和實現化兩個角色,使它們能夠分別進行變化;而在初步設計完成以後,當發現系統與已有類沒法協同工做時,能夠採用適配器模式。但有時候在設計初期也須要考慮適配器模式,特別是那些涉及到大量第三方應用接口的狀況。code

橋接+適配器

4. 優缺點

  • 優勢
  1. 分離抽象接口機器實現部分。橋接模式使用「對象間的關聯關係」解耦了抽象和實現之間固有的綁定關係,使得抽象和實現能夠沿着各自的維度來變化。
  2. 在不少狀況下,橋接模式能夠取代多層繼承方案,多層繼承方案違背了「單一職責原則」,複用性較差,且類的個數很是多,橋接模式是比多層繼承方案更好的解決方法,它極大減小了子類的個數。
  3. 橋接模式提升了系統的可擴展性,在兩個變化維度中任意擴展一個維度,都不須要修改原有系統,符合「開閉原則」。
  • 缺點
  1. 橋接模式的使用會增長系統的理解與設計難度,因爲關聯關係創建在抽象層,要求開發者一開始就針對抽象層進行設計與編程。
  2. 橋接模式要求正確識別出系統中兩個獨立變化的維度,所以其使用範圍具備必定的侷限性,如何正確識別兩個獨立維度也須要必定的經驗積累。

5. 適用場景

  1. 若是一個系統須要在抽象化和具體化之間增長更多的靈活性,避免在兩個層次之間創建靜態的繼承關係,經過橋接模式可使它們在抽象層創建一個關聯關係。
  2. 抽象部分」和「實現部分」能夠以繼承的方式獨立擴展而互不影響,在程序運行時能夠動態將一個抽象化子類的對象和一個實現化子類的對象進行組合,即系統須要對抽象化角色和實現化角色進行動態耦合。
  3. 一個類存在兩個(或多個)獨立變化的維度,且這兩個(或多個)維度都須要獨立進行擴展。
  4. 對於那些不但願使用繼承或由於多層繼承致使系統類的個數急劇增長的系統,橋接模式尤其適用。

6. 我的理解

在軟件開發中若是一個類或一個系統有多個變化維度時,均可以嘗試使用橋接模式對其進行設計,而不是採用多層繼承的方案。將其抽象部分與實現部分分離,下降系統的複雜度。

參考

  1. Java設計模式-劉偉
相關文章
相關標籤/搜索