(轉)設計模式 橋接模式(結構性模式)
What:
將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
Why:
優點:
1.抽象和實現的分離。
2.優秀的擴充套件能力。
3.實現細節對客戶透明。
缺點:
1.增加了系統的理解和設計難度,由於聚合關聯關係建立在抽象層,要求開發者針對抽象進行設計和程式設計。
2.要求正確識別出系統中兩個獨立變化的維度,因此其使用範圍有一定的侷限性。
Where:
1.一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴充套件;
2.對於那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用。
How:
橋接模式有以下幾種角色:
抽象角色(Abstraction):
擴充套件抽象角色(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
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處