當系統有兩個獨立變化的維度(如:訊息操作類型:基本/進階 × 儲存方式:SQL/XML/JSON/NoSQL)時,若用繼承組合會導致類別爆炸(基本SQL、基本XML、進階SQL、進階XML...)。橋接模式將「抽象部分」與「實現部分」分離,使它們可以獨立變化:抽象層定義高層操作介面,持有實現層介面參考,委派具體工作;實現層定義底層操作介面,由具體實現類別實作。本文以訊息系統為例,展示 Message/MyMessage(抽象維度)與 SqlMessage/XmlMessage(實現維度)如何獨立擴展並自由組合。
Message,定義高層操作 Get()、Insert(),持有 AbstractMessage 實現參考,委派呼叫。MyMessage,繼承 Message,擴展高層行為(如:結果後綴標記),不涉及底層儲存邏輯。AbstractMessage,定義底層操作 Get()、Insert() 介面。SqlMessage、XmlMessage,實作具體儲存邏輯。
public abstract class AbstractMessage
{
public abstract List<MessageModel> Get();
public abstract bool Insert(MessageModel mm);
}
public class SqlMessage : AbstractMessage
{
public override List<MessageModel> Get()
{
var l = new List<MessageModel>();
l.Add(new MessageModel("SQL方式獲取Message", DateTime.Now));
return l;
}
public override bool Insert(MessageModel mm) { return true; }
}
public class XmlMessage : AbstractMessage
{
public override List<MessageModel> Get()
{
var l = new List<MessageModel>();
l.Add(new MessageModel("XML方式獲取Message", DateTime.Now));
return l;
}
public override bool Insert(MessageModel mm) { return true; }
}
public class Message
{
private AbstractMessage _abstractMessage;
public AbstractMessage AbstractMessage
{
get { return _abstractMessage; }
set { _abstractMessage = value; }
}
public virtual List<MessageModel> Get() => _abstractMessage.Get();
public virtual bool Insert(MessageModel mm) => _abstractMessage.Insert(mm);
}
關鍵:抽象化「擁有」實現化(組合關係),而非「是一個」實現化(繼承關係)。
public class MyMessage : Message
{
public override List<MessageModel> Get()
{
var l = base.Get(); // 呼叫基類委派 → 實現化.Get()
foreach (var mm in l)
mm.Message += "(RefinedAbstraction)"; // 高層增強:標記來源
return l;
}
}
var m = new MyMessage(); // 選擇抽象維度:進階版
m.AbstractMessage = new SqlMessage(); // 選擇實現維度:SQL
Response.Write(m.Insert(new MessageModel("插入", Now)));
Response.Write(m.Get()[0].Message); // SQL方式獲取Message(RefinedAbstraction)
m.AbstractMessage = new XmlMessage(); // 切換實現維度:XML
Response.Write(m.Insert(new MessageModel("插入", Now)));
Response.Write(m.Get()[0].Message); // XML方式獲取Message(RefinedAbstraction)
True
SQL方式獲取Message(RefinedAbstraction) 2007-5-13 19:11:19
True
XML方式獲取Message(RefinedAbstraction) 2007-5-13 19:11:19
完美驗證:抽象維度(MyMessage 增強行為)與實現維度(SQL/XML 儲存邏輯)正交組合,互不影響。
| 維度 | 橋接模式 | 策略模式 | 適配器模式 |
|---|---|---|---|
| 意圖 | 分離抽象與實現,雙向獨立擴展 | 封裝可互換演算法 | 轉換不相容介面 |
| 關係 | 抽象「擁有」實現(組合) | Context「擁有」Strategy | Adapter「包裝」Adaptee |
| 變化維度 | 兩個獨立維度 | 單一演算法維度 | 介面不匹配 |
| 客戶端感知 | 知曉抽象與實現兩層 | 只知 Context | 只知 Target 介面 |
若有 3 個維度(如:UI 主題 × 渲染引擎 × 平台),可串聯橋接:
Abstraction → ImplementorA → ImplementorB → ImplementorC
或使用「橋接的橋接」:抽象層持有多個實現介面參考。
public class MessageAbstraction
{
private readonly IMessageImplementor _implementor;
public MessageAbstraction(IMessageImplementor implementor)
=> _implementor = implementor;
// 委派方法...
}
// DI 註冊
services.AddTransient();
services.AddTransient();
// 客戶端注入 MessageAbstraction,實現由容器決定
優點:編譯期完全解耦、測試易 Mock、執行期動態切換實現、支援多實現共存(Named Services)。
DbConnection (Abstraction) ↔ SqlConnection/OracleConnection (Implementor),DbCommand、DbDataReader 同理。Stream (Abstraction) ↔ FileStream/MemoryStream/NetworkStream (Implementor),BufferedStream 為 RefinedAbstraction。IDatabaseProvider 介面,SQL Server/PostgreSQL/MySQL/SQLite 實現。ILogger (Abstraction) ↔ ConsoleLogger/JsonLogger/EventLogLogger (Implementor)。abstraction.Implementor = newImpl。橋接模式以「組合取代繼承」,將系統拆解為「抽象維度」與「實現維度」兩個正交層次,實現雙向獨立擴展與自由組合。本範例以 Message/MyMessage(操作層級)× SqlMessage/XmlMessage(儲存方式)為例,完整展示了抽象化委派實現化、修正抽象化增強高層行為、客戶端動態組合的核心機制。實務中,從 ADO.NET Provider、Stream 架構、EF Database Provider 到跨平台 UI 渲染、日誌輸出、訊息隊列客戶端,橋接模式是大型框架、庫、中間件實現「多實現、可插拔、可測試」架構的基石。掌握其核心——「識別正交維度、定義實現介面、抽象層委派組合、DI 容器注入」,能讓你在設計需要支援多種底層實現、多種高層功能組合的系統時,構建出極具彈性與可維護性的雙層架構。