橋接模式

2018年11月2日09:26:00html

橋接模式(bridge pattern)

定義

記憶中最深的就是那個外婆橋java

家和外婆在兩邊設計模式

在家裏想吃和想玩的ide

在外婆家都有測試

橋接模式(bridge pattern),將抽象部分與它的實現部分分離,是它們均可以獨立的變化。————《設計模式:可複用面向對象軟件的基礎》this

橋接模式是一種對象結構型模式。操作系統

使用場景

一、若是一個系統須要在構件的抽象化角色和實現化角色之間增長更多的靈活性,避免在兩個層次之間創建靜態的繼承聯繫,經過橋接模式可使它們在抽象層創建一個關聯關係。設計

二、抽象化角色和實現化角色能夠以繼承的方式獨立擴展而互不影響,在程序運行時能夠動態將一個抽象化子類的對象和一個實現化子類的對象進行組合,即系統須要對抽象化角色和實現化角色進行動態耦合。3d

三、一個類存在兩個獨立變化的維度,且這兩個維度都須要進行擴展。代理

四、雖然在系統中使用繼承是沒有問題的,可是因爲抽象化角色和具體化角色須要獨立變化,設計要求須要獨立管理這二者。對於那些不但願使用繼承或由於多層次繼承致使系統類的個數急劇增長的系統,橋接模式尤其適用。

抽象和實現分離,各自變化。

類存在兩個獨立變化的維度,抽象表明一個,實現表明一個。

組合/聚合複用原則

組合/聚合複用原則(CARP:Composite/Aggregate Reuse Priciple),儘可能使用組合/聚合複用原則,儘可能不要使用類繼承。————《Java與設計模式》

聚合表示一種弱的‘擁有’關係,體現的是A對象能夠包含B對象,但B對象不是A對象的一部分;組合則是一種強的‘擁有’關係,體現了嚴格的部分和總體的關係,部分和總體的生命週期同樣。————《設計模式解釋》

組合/聚合複用原則的好處是,優先使用對象的組合/聚合複用原則將有助於你保持每一個類被封裝,並被集中在單個任務上,這樣類和類繼承層次會保持較小規模,而且不太可能增加爲不可控制的龐然大物。————《設計模式:可複用面向對象軟件的基礎》

組合關係就是一我的有手腳,聚合是一我的有錢。

示例代碼:

public class Person {
    private Hand hand = new Hand();
    private Foot foot = new Foot();
    private Money money;

    public Person(){}
    public Person(Money money){
        this.money = money;
    }
}
public class Hand{}
public class Foot{}
public class Money{}

手腳是一個正常人生來就有的,可是錢這個東西,身外之物。聚合是鬆耦合的,組合相對來講就是耦合性比較強。

橋接模式是應用組合/聚合複用原則(CARP)。其實還有不少其餘對象結構型模式都是應用了這個原則的,如代理模式、裝飾者模式、對象適配者模式等,以此來達到鬆耦合的目的。

角色

抽象化角色(Abstraction):抽象化給出的定義,並保存一個對實現化對象的引用

擴充抽象化角色(RefinedAbstraction)【修正抽象化(Refined Abstraction)角色】:擴展抽象化角色,改變和修正父類對抽象化的定義

實現化角色(Implementor):實現化角色的接口,但不給出具體的實現

具體實現化角色(ConcreteImplementor):具體實現

圖示

橋接模式結構圖

抽象(Abstraction)和實現(Implementor)以組合的方式關聯起來,抽象的動做行爲是由實現來執行。抽象和實現均可以有它們各自的變化,被多個子類繼承,擁有不一樣的功能。

代碼示例

故事背景:城市A和城市B是分隔兩岸的兩座城市,他們經過一座擁有悠久歷史的橋鏈接起來。城市A人文氣息濃厚,商店林立,人來人往,熙熙攘攘。城市B工業氣息濃厚,各類機器和手工做坊相輝映,在重複的工序中輸出產品。城市A和城市B交互的模式,通常是城市A下訂單,城市B完成訂單。

這裏對於訂單來講有兩個維度,一個是種類:蛋糕或糖果,一種是製做方式:手工或機器製做。若是沒有使用橋接模式的話,就有四種組合方式,就是四個類,可是若是增長了種類或者製做方式的話,須要繼續計算組合方式,類增加的速度不是咱們想要的。當使用了橋接模式以後,添加種類或製做方式只須要添加繼承抽象化對象或者實現化對象增長鬚要變化的維度的對象便可。

抽象化角色(OrderAbstraction.java):

// 訂單
public abstract class OrderAbstraction {
    protected FactoryImplementor factoryImplementor;
    
    public OrderAbstraction(FactoryImplementor factoryImplementor) {
        this.factoryImplementor = factoryImplementor;
    }
    
    public abstract void provide();
}

擴充抽象化角色(CakeOrderRefinedAbstraction.java):

// 蛋糕訂單
public class CakeOrderRefinedAbstraction extends OrderAbstraction {
    private int count;
    private String orderName = "蛋糕";

    public CakeOrderRefinedAbstraction(int count, FactoryImplementor factoryImplementor) {
        super(factoryImplementor);
        this.count = count;
    }

    @Override
    public void provide() {
        factoryImplementor.provide(count, orderName);
    }

}
// 糖果訂單
public class CandyOrderRefinedAbstraction extends OrderAbstraction {
    private int count;
    private String orderName = "糖果";

    public CandyOrderRefinedAbstraction(int count, FactoryImplementor factoryImplementor) {
        super(factoryImplementor);
        this.count = count;
    }

    @Override
    public void provide() {
        factoryImplementor.provide(count, orderName);
    }

}

實現化角色(FactoryImplementor.java):

// 工廠
public interface FactoryImplementor {
    public void provide(int count, String orderName);
}

具體實現化角色(HandworkFactoryConcreteImplementor.java、MachineFactoryConcreteImplementor.java):

// 手工做坊
public class HandworkFactoryConcreteImplementor implements FactoryImplementor {

    public void provide(int count, String orderName) {
        float time = (float)(count * 1);
        System.out.println("手工使用了" + time + "小時,完成了" + count + "份" + orderName);
    }

}
// 工廠機器
public class MachineFactoryConcreteImplementor implements FactoryImplementor {

    public void provide(int count, String orderName) {
        float time = (float)(count * 0.5);
        System.out.println("機器使用了" + time + "小時,完成了" + count + "份" + orderName);
    }

}

測試類(BridgePatternTest.java):

public class BridgePatternTest {

    public static void main(String[] args) {
        // 手工蛋糕訂單
        OrderAbstraction handworkCake = 
                new CakeOrderRefinedAbstraction(10, 
                        new HandworkFactoryConcreteImplementor());
        // 機器蛋糕訂單
        OrderAbstraction machineCake = 
                new CakeOrderRefinedAbstraction(10, 
                        new MachineFactoryConcreteImplementor());
        // 手工糖果訂單
        OrderAbstraction handworkCandy = 
                new CandyOrderRefinedAbstraction(10, 
                        new HandworkFactoryConcreteImplementor());
        // 機器糖果訂單
        OrderAbstraction machineCandy = 
                new CandyOrderRefinedAbstraction(10, 
                        new MachineFactoryConcreteImplementor());

        handworkCake.provide();
        machineCake.provide();
        handworkCandy.provide();
        machineCandy.provide();
    }
}

測試結果:
橋接模式測試結果

結果代表了:抽象和實現分離,各自變化。訂單存在着兩個維度變化,一個是種類,一個是製造方式,種類分爲蛋糕和糖果,製造方式有手工和機器。

其餘實例

手機軟件也有種類和運行在不一樣的操做系統上兩個維度的變化,種類有通信錄、短信等,操做系統IOS,Android等,這樣就適用於橋接模式。

若是須要開發一個跨平臺視頻播放器,能夠在不一樣操做系統平臺(如Windows、Linux、Unix等)上播放多種格式的視頻文件,常見的視頻格式包括MPEG、RMVB、AVI、WMV等。一樣適用於橋接模式。

與適配器模式的區別

橋接模式是在設計之初,認爲抽象和現實都存在多維的變化,並且抽象和實現的變化是不相關的,在可預見的狀況下作出的選擇,適配器模式是系統已經成熟到沒法修改或者修改的工做量沒法估量的時候,可是又想複用當前的功能的時候使用,或者使用第三方組件的時候使用。不少狀況下,橋接模式就是使用了對象適配器模式實現的。適配器模式能夠參考本人適配者模式

優勢

  • 一、抽象和實現分離

  • 二、多維度變化

缺點

  • 一、增長系統的設計和理解難度

總結

當在系統設計初期,發現抽象和實現存在各自的變化或某個類由兩個不相關的維度描述時,能夠考慮橋接模式。

2018年11月16日21:56:11

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息