問題:
在物件導向的設計中,抽象是一個很重要的概念,所謂抽象就是忽略一類對象的特殊特性,提出一些共有的特性,暫時忽略一些細節,而對與此類對象的變化可以使用繼承的手段在子類中完成,換言之,用繼承來應對抽象的變化。在軟體系統中,當抽象由於某種原因也容易變動,使得對象從兩個維度或更多方向上發生改變。使用繼承方案往往違背了類的單一職責原則(即一個類只有一個變化的原因),複用性比較差。Bridge模式是比繼承方案更好的解決方案。
定義:
橋接模式(Bridge Pattern),將抽象部分與它的實現部分分離,使的抽象和實現都可以獨立地變化。
意圖:
Bridge模式,系統被分為抽象(Abstraction)和實現(Implemetor)兩個相對獨立的部分抽象部(這裡所謂的“抽象”與“實現”的含義不是指子類繼承抽象基類實現具體的方法,抽象是指需求的抽象,而實現是指通過對象組合實現使用者的需求),這兩個部分可以互相獨立地進行修改。Implemetor(還可以擴充到更多變化方向)部分的抽象,以抽象類別的形式組合到抽象(Abstraction)部分的抽象類別中,在抽象部分的主實現對象RefinedAbstraction中隔離了對實現部分(Implemetor)變化對象的具體實現(ConcreteImplemetor)的依賴。
參與者:
•抽象化(Abstraction)角色:抽象化給出的定義,並儲存一個對實現化對象的引用。
•修正抽象化(Refined Abstraction)角色:擴充抽象化角色,改變和修正父類對抽象化的定義。
•實現化(Implementor)角色:這個角色給出實現化角色的介面,但不給出具體的實現。實現化角色給出的底層操作,抽象化角色給出基於底層操作的更高一層的操作。
•具體實現化(Concrete Implementor)角色:這個角色給出實現化角色介面的具體實現
UML:
執行個體說明:
諾基亞手機工廠
抽象的手機工廠要應對不同型號的手機(N8,N9的生產方式可能不一樣)生產差異的變化,又要應對不同網路類型(GSM,CDMA生產方式可能不一樣)的差異變化
uml:
•使用繼承模式:
•使用橋接模式:
代碼:
/// <summary>
/// 手機生產抽象角色 抽象介面
/// </summary>
public abstract class PhoneFactory
{
protected PhoneNetType phoneNetType;
public void SetNetType(PhoneNetType _phoneNetType)
{
phoneNetType = _phoneNetType;
}
public abstract void Create();
}
/// <summary>
/// 手機生產 抽象角色 RefinedAbstraction
/// </summary>
public class Factory_N8 : PhoneFactory
{
public override void Create()
{
phoneNetType.CreatePhone();
System.Console.WriteLine("我是N8");
}
}
/// <summary>
/// 手機生產 抽象角色 RefinedAbstraction
/// </summary>
public class Factory_N9 : PhoneFactory
{
public override void Create()
{
phoneNetType.CreatePhone();
System.Console.WriteLine("我是N9");
}
}
/// <summary>
/// 手機生產 Implementor
/// </summary>
public abstract class PhoneNetType
{
public abstract void CreatePhone();
}
/// <summary>
/// 手機生產 ConcreteImplementor
/// </summary>
public class Factory_Csm : PhoneNetType
{
public override void CreatePhone()
{
System.Console.WriteLine("我是一款GSM網路手機。");
}
}
/// <summary>
/// 手機生產 ConcreteImplementor
/// </summary>
public class Factory_Cdma : PhoneNetType
{
public override void CreatePhone()
{
System.Console.WriteLine("我是一款CDMA網路手機。");
}
}
/// <summary>
/// 用戶端測試代碼
/// </summary>
public void BridgeTest()
{
PhoneFactory pf = new Factory_N8();
pf.SetNetType(new Factory_Csm());
pf.Create();
}
優點:
•Bridge模式使用“合成/彙總複用原則”解耦了抽象和實現之間的高耦合關係,使得抽象和實現可以沿著各自的維度來變化(通過各自繼承)。
•抽象化角色和具體化角色之間增加更多的靈活性,當有新的抽象或實現方式時,只需要繼承一個抽象和繼承一個實現即可。
•實現化角色的任何改變不影響用戶端。
缺點:
•Bridge模式不能應對維度數量的變化,如果要重新抽象出另外一個維度類型,則需要修改抽象角色,將新的實現(Implemetor)組合進抽象(Abstraction)中,違反開閉原則
應用情景:
當系統有多維角度分類時,而每一種分類又有非常強的變化,時使用橋接模式比較合適