(轉)設計模式 橋接模式(結構性模式)

What:

將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

Why:

優點:

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

缺點:

1.增加了系統的理解和設計難度,由於聚合關聯關係建立在抽象層,要求開發者針對抽象進行設計和編程。
2.要求正確識別出系統中兩個獨立變化的維度,因此其使用範圍有一定的侷限性。

Where:

1.一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展;
2.對於那些不希望使用繼承或因爲多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤爲適用。

How:

橋接模式有以下幾種角色:

抽象角色(Abstraction): 抽象的定義,並保存一個Implementor對象的引用。

擴展抽象角色(RefineAbstraction): 拓展Abstraction。

抽象實現角色(Implementor): 定義實現類的接口,提供基本操作,其實現交給子類實現。

具體實現角色(ConcreteImplementor): 實現Implementor接口,在程序運行時,子類對象將替換其父類對象,提供給Abstraction具體的業務操作方法。

示例:家電電器有很多種,也有很多品牌,電器和品牌存在關係。

 
例子1

如圖所示,如果按照這樣的設計,每增加一種電器就需要對應的綁定品牌;另一種情況是,每增加一個品牌就需要在對應的電器下添加。這樣的話會導致出現許多重複性的代碼,而且耦合度也很高。

如果添加新的品牌或者新的電器而不會改動先有的類,該怎麼設計呢?

根據橋接模式,代碼可以設計成下圖的流程


 
例子2

ElectricAppliance接口:

public interface ElectricAppliance {
    String description();
}

AirConditioner類、WashingMachine類、WaterHeater類:

public class AirConditioner implements ElectricAppliance {

    private final String name = "空調";

    @Override
    public String description() {
        return name;
    }
}

public class WashingMachine implements ElectricAppliance {

    private final String name = "洗衣機";

    @Override
    public String description() {
        return name;
    }
}

public class WaterHeater implements ElectricAppliance {

    private final String name = "熱水器";

    @Override
    public String description() {
        return name;
    }
}

Brand抽象類:

public abstract class Brand {

    protected ElectricAppliance electricAppliance;

    public Brand(ElectricAppliance electricAppliance) {
        this.electricAppliance = electricAppliance;
    }

    abstract String description();
}

Gree類、Haier類、Midea類:

public class Gree extends Brand {

    private final  String name = "格力";

    public Gree(ElectricAppliance electricAppliance) {
        super(electricAppliance);
    }

    @Override
    public String description() {
        return name + electricAppliance.description();
    }
}

public class Haier extends Brand{

    private final  String name = "海爾";

    public Haier(ElectricAppliance electricAppliance) {
        super(electricAppliance);
    }

    @Override
    public String description() {
        return name + electricAppliance.description();
    }
}

public class Midea extends Brand{

    private final  String name = "美的";

    public Midea(ElectricAppliance electricAppliance) {
        super(electricAppliance);
    }

    @Override
    public String description() {
        return name + electricAppliance.description();
    }
}

Test:測試類

public class Test {
    public static void main(String[] args) {
        Brand midea = new Midea(new WashingMachine());
        System.out.println(midea.description());

        Brand gree1 = new Gree(new WashingMachine());
        System.out.println(gree1.description());

        //添加新電器
        Brand gree2 = new Gree(new AirConditioner());
        System.out.println(gree2.description());

        //添加新品牌
        Brand haier1 = new Haier(new WashingMachine());
        System.out.println(haier1.description());
        Brand haier2 = new Haier(new WaterHeater());
        System.out.println(haier2.description());
    }
}

輸出結果:

美的洗衣機
格力洗衣機
格力空調
海爾洗衣機
海爾熱水器

總結

以上例子中,抽象類Brand相當於橋樑,連接了品牌和電器兩個抽象對象。當有新的品牌或者電器對象添加的時候,都不用改動原有的類,直接繼承或者實現接口就可以,遵循了開閉原則。但橋接模式也存在侷限性,因爲擴展抽象類需要繼承,Java只可以單繼承,而且繼承意味着強耦合,當父類有改動的話,子類都需要改動;另一方面,使用橋接模式需要識別出系統中兩個獨立變化的部分,加大了設計和維護的難度。


作者:禿頭的路上
鏈接:https://www.jianshu.com/p/61ad71954c74
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章