大話設計模式—橋接模式

May的部落格發表於2016-04-02

橋接(Bridge)是用於把抽象化與實現化解耦,使得二者可以獨立變化。這種型別的設計模式屬於結構型模式,它通過提供抽象化和實現化之間的橋接結構,來實現二者的解耦。主要解決:在有多種可能會變化的情況下,用繼承會造成類爆炸問題,擴充套件起來不靈活。這種模式涉及到一個作為橋接的介面,使得實體類的功能獨立於介面實現類。這兩種型別的類可被結構化改變而互不影響。

大話設計模式中程傑老師給出的定義是,橋接模式:將抽象部分與實現部分分離,使它們都可以獨立的變化

首先我們來看一個問題:現在我有一個N品牌一個M品牌的手機,兩個品牌的手機都有兩種功能:遊戲和通訊錄,我們該如何實現?

依據物件導向的理論設計,我們有兩種設計思想:

實現一:先有一個品牌,多個品牌就抽象出一個品牌抽象類,對於每個功能,就都繼承各自的品牌;

這裡寫圖片描述

實現二:先有功能,多個功能就可以抽象出一個抽象功能類,對於每個手機品牌,分別去繼承各個功能;

這裡寫圖片描述

上面的設計完美的遵循了物件導向的原則,但是,問題也隨之而來,如果我現在需要給每個品牌都增加一個MP3播放器功能,我們該怎麼辦?

對於實現一,我們需要在每個品牌下面分別增加一個MP3播放器功能;對於實現二,我們需要在手機軟體下增加一個抽象的MP3播放器功能,然後各個手機品牌再分別去繼承這個功能。

如果我們需要再增加一個手機品牌呢?那我們要改動的地方就越來越多了。顯然這種設計似乎有問題的。

但我們學會使用物件導向的繼承時,確實感覺它非常強大,但是並不是所有的情況都可以使用物件導向的繼承,而且有很多情況下,使用繼承會帶來麻煩。比如,物件的繼承關係是在編譯時就定義好了,所以無法在執行時改變從父類繼承的實現。子類實現與它的父類有非常緊密的依賴關係,以至於父類實現中的任何變化都必然會導致子類發生變化。當你需要複用子類時,如果繼承下來的實現不適合解決新的問題,則父類必須重寫或被其它更適合的類替換。這種依賴關係限制了靈活性並最終限制了複用性。

就像我們上面的兩種實現,如果不斷地增加新的手機品牌和功能,類會越來越多。怎麼解決呢?物件導向設計中還有一個很重要的原則合成/聚合複用原則,即優先使用物件合成/聚合,而不是類繼承

合成表示一種強的擁有關係,體現了嚴格的部分和整體的關係,部分和整體的生命週期一樣,打個比方:人有兩個胳膊,胳膊和人就是部分和整體的關係,人去世了,那麼胳膊也就沒用了,也就是說胳膊和人的生命週期是相同的,合成關係用實心的菱形+實線來表示。

合成/聚合複用規則的好處:優先使用物件的合成/聚合將有助於你保持每個類被封裝,並被集中在單個任務上。這樣類和類繼承層次會保持在一個較小的規模,並且不太可能增長為不可控制的龐然大物。

下面我麼來看看遵循合成/聚合複用規則的實現三:

這裡寫圖片描述

橋接模式的核心意圖就是把這些實現獨立出來,讓它們各自的變化。這就使得每種實現的變化不會影響其它的實現,從而達到應對變化的目的。

這裡寫圖片描述

程式碼實現:

package com.bridge;

public abstract class Implementor {

    public abstract void operation();

}
package com.bridge;

public class ConcreteImplementorA extends Implementor {

    @Override
    public void operation() {
        System.out.println("具體實現A執行");
    }

}
package com.bridge;

public class ConcreteImplementorB extends Implementor {

    @Override
    public void operation() {
        System.out.println("具體實現B執行");
    }

}
package com.bridge;

public abstract class Abstraction {

    protected Implementor implementor;

    public void setImplementor(Implementor implementor){
        this.implementor = implementor;
    }

    public void operation(){
        implementor.operation();
    }

}
package com.bridge;

public class RefinedAbstraction extends Abstraction {

    public void operation(){
        implementor.operation();
    }

}
package com.bridge;

public class BridgePatternDemo {

    public static void main(String[] args) {

        Abstraction ab = new RefinedAbstraction();

        ab.setImplementor(new ConcreteImplementorA());
        ab.operation();

        ab.setImplementor(new ConcreteImplementorB());
        ab.operation();
    }

}

執行結果:

具體實現A執行
具體實現B執行

應用例項: 牆上的開關,可以看到的開關是抽象的,不用管裡面具體怎麼實現的。

優點:

1、抽象和實現的分離。
2、優秀的擴充套件能力。
3、實現細節對客戶透明。

缺點

橋接模式的引入會增加系統的理解與設計難度,由於聚合關聯關係建立在抽象層,要求開發者針對抽象進行設計與程式設計。

使用場景:

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

2、對於那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用。

3、一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴充套件,對於兩個獨立變化的維度,使用橋接模式再適合不過了。

相關文章