介紹
橋接模式(Bridge):將抽象部分與它的實現部分分離,使它們可以獨立地變化。
抽象與它的實現分離指的是抽象類和它的派生類用來實現自己的對象。
結構圖
角色:
Abstraction:抽象化角色。它的主要職責是定義該角色的行爲,同時保存一個對實現角色的引用,該角色一般是抽象類
Implementor:實現化角色。它是接口或者抽象類,定義角色必須的行爲和屬性
RefineAbstraction:修正抽象化角色。它引用實現角色對抽象化角色進行修正
ConcreteImplementor:具體實現化角色。它實現接口或抽象類定義的方法和屬性。
橋接模式(橋樑模式)中的幾個名詞比較拗口,但是隻要記住一句話:抽象角色引用實現角色,或者說抽象角色的部分實現是由實現角色完成的。
基本代碼
客戶端代碼
static void Main(string[] args)
{
Abstraction ab = new RefinedAbstraction();
ab.SetImplementor(new ConcreteImplementorA());
ab.Operation();
ab.SetImplementor(new ConcreteImplementorB());
ab.Operation();
Console.Read();
}
Implementor類
abstract class Implementor
{
public abstract void Operation();
}
ConcreteImplementorA和ConcreteImplementorB等派生類
class ConcreteImplementorA : Implementor
{
public override void Operation()
{
Console.WriteLine("具體實現A的方法執行");
}
}
class ConcreteImplementorB : Implementor
{
public override void Operation()
{
Console.WriteLine("具體實現B的方法執行");
}
}
Abstraction 類
class Abstraction
{
protected Implementor implementor;
public void SetImplementor(Implementor implementor)
{
this.implementor = implementor;
}
public virtual void Operation()
{
implementor.Operation();
}
}
RefinedAbstraction類
class RefinedAbstraction : Abstraction
{
public override void Operation()
{
implementor.Operation();
}
}
例子
手機品牌M中有遊戲“魂鬥羅”而把“魂鬥羅”安裝在手機品牌N上不能運行,如何解決這一問題呢?
代碼結構圖
代碼實現
客戶端代碼
static void Main(string[] args)
{
HandsetBrand ab;
ab = new HandsetBrandN();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
ab = new HandsetBrandM();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
Console.Read();
}
手機軟件
abstract class HandsetSoft
{
public abstract void Run();
}
遊戲、通訊等具體類
class HandsetGame : HandsetSoft
{
public override void Run()
{
Console.WriteLine("運行手機遊戲");
}
}
手機通訊錄
class HandsetAddressList : HandsetSoft
{
public override void Run()
{
Console.WriteLine("運行手機通訊錄");
}
}
手機品牌類
abstract class HandsetBrand
{
protected HandsetSoft soft;
//設置手機軟件
public void SetHandsetSoft(HandsetSoft soft) //品牌需要關注軟件,所以可在機器中安裝軟件(設置手機軟件),以備運行
{
this.soft = soft;
}
//運行
public abstract void Run();
}
品牌N 品牌M具體類 //手機品牌N
class HandsetBrandN : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
//手機品牌M
class HandsetBrandM : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
如果需要增加一個功能,,例如MP3音樂播放功能,那麼只要增加這個類就行了,不會用影響其他任何類。類的個數增加也只是一個
class HandsetMP3 : HandsetSoft
{
public override void Run()
{
Console.WriteLine("運行MP3播放");
}
}
如果此時還需要在增加一個品牌,那麼只需要增加一個品牌的子類就可以了。個數也是一個,不會影響其他類的改動
class HandsetBrandS : HandsetBrand
{
public override void Run()
{
soft.Run();
}
}
橋接模式的優點
1.抽象和分離。這也是橋接模式的看主要特點,它完全是爲了解決繼承的缺點而提煉出的設計模式。在該模式下,實現可以不受抽象的約束,不用再綁定一個固定的抽象層次上。
2.優秀的擴充能力。增加實現、增加抽象都沒有問題,只要對外暴露的接口層允許這樣的變化,我們已經把變化的可能性減到最小
3.實現細節對客戶透明。客戶不關心細節的實現,它已經由抽象層通過聚合關係完成封裝。
橋接模式的缺點
1.會增加系統的理解與設計難度,由於關聯關係建立在抽象層,要求開發者一開始就針對抽象層進行設計與編程
2.正確識別出系統中兩個獨立變化的維度不是一件容易的事情
適用場景
1.不希望或不使用繼承的場景例如 繼承層次過度、無法更細化設計顆粒等場景,需要考慮使用橋接模式
2.接口或抽象類不穩定的場景
例如接口不穩定還想通過實現或繼承來實現業務需求,那是得不償失的,也是比較失敗的做法。
3.重要性要求較高的場景
設計的顆粒度越細,則被重用的可能性越大,而採用繼承則受父類的限制,不可能出現太細的顆粒度