橋接模式是結構型設計模式中極具價值且相對複雜的一員。它的核心在於「將抽象化與實現化解耦,使二者可獨立變化」。掌握此模式有助於深入理解面向對象設計原則,特別是開閉原則(OCP)與組合/聚合復用原則(CARP),進而養成良好的設計風格。
雖然《Java 與模式》一書認為橋接模式使用頻率不高,但我更贊同《Design Patterns Explained》作者 Alan Shalloway 與 James R. Trott 的觀點:橋接模式蘊含了許多設計模式的關鍵思想,比其他模式更實用、更複雜。
指存在於多個實體中的共同概念聯繫。作為一個過程,即忽略部分資訊,將不同實體視為同一實體處理。
抽象化所給出的具體實現。
將兩實體間的強關聯(繼承關係)轉為弱關聯(組合/聚合關係),使抽象化與實現化可相對獨立演化。

系統包含兩個平行的等級結構:
四大核心角色:
// Bridge pattern -- Structural example
using System;
// 抽象化
class Abstraction {
protected Implementor implementor;
public Implementor Implementor { set { implementor = value; } }
virtual public void Operation() { implementor.Operation(); }
}
// 實現化介面
abstract class Implementor {
abstract public void Operation();
}
// 修正抽象化
class RefinedAbstraction : Abstraction {
override public void Operation() { implementor.Operation(); }
}
// 具體實現化 A
class ConcreteImplementorA : Implementor {
override public void Operation() { Console.WriteLine("ConcreteImplementorA Operation"); }
}
// 具體實現化 B
class ConcreteImplementorB : Implementor {
override public void Operation() { Console.WriteLine("ConcreteImplementorB Operation"); }
}
// 客戶端測試
public class Client {
public static void Main(string[] args) {
Abstraction abstraction = new RefinedAbstraction();
abstraction.Implementor = new ConcreteImplementorA();
abstraction.Operation();
abstraction.Implementor = new ConcreteImplementorB();
abstraction.Operation();
}
}
《敏捷軟件開發》中的 Modem 案例生動詮釋了橋接模式的威力。早期系統中,Modem 介面派生出 HayesModem、USRoboticsModem 等,符合 OCP/LSP/DIP。後因專用調制解調器(無需撥號)出現,若讓 DedicatedModem 繼承 Modem 並將 dial/hangup 實現為空,會導致後續擴展(如國際長撥號碼長度變更)波及無關的 DedUser 代碼,產生有害依賴。

使用橋接模式,將「連接策略」與「硬體實現」分離為兩個獨立等級結構,透過組合關係橋接:

此結構雖較複雜,但完全隔離了變化維度:新增硬體只需擴展實現化層次,新增連接策略只需擴展抽象化層次,互不干擾,且不影響現有客戶端代碼。
// Bridge pattern -- Real World example
using System;
using System.Collections;
// 抽象化:業務對象
class BusinessObject {
private DataObject dataObject;
protected string group;
public BusinessObject(string group) { this.group = group; }
public DataObject DataObject { set { dataObject = value; } get { return dataObject; } }
virtual public void Next() { dataObject.NextRecord(); }
virtual public void Prior() { dataObject.PriorRecord(); }
virtual public void New(string name) { dataObject.NewRecord(name); }
virtual public void Delete(string name) { dataObject.DeleteRecord(name); }
virtual public void Show() { dataObject.ShowRecord(); }
virtual public void ShowAll() {
Console.WriteLine("Customer Group: {0}", group);
dataObject.ShowAllRecords();
}
}
// 修正抽象化:客戶業務對象
class CustomersBusinessObject : BusinessObject {
public CustomersBusinessObject(string group) : base(group) {}
override public void ShowAll() {
Console.WriteLine(); Console.WriteLine("------------------------");
base.ShowAll();
Console.WriteLine("------------------------");
}
}
// 實現化:數據對象介面
abstract class DataObject {
abstract public void NextRecord();
abstract public void PriorRecord();
abstract public void NewRecord(string name);
abstract public void DeleteRecord(string name);
abstract public void ShowRecord();
abstract public void ShowAllRecords();
}
// 具體實現化:客戶數據對象
class CustomersDataObject : DataObject {
private ArrayList customers = new ArrayList();
private int current = 0;
public CustomersDataObject() {
customers.Add("Jim Jones"); customers.Add("Samual Jackson");
customers.Add("Allen Good"); customers.Add("Ann Stills");
customers.Add("Lisa Giolani");
}
public override void NextRecord() { if (current <= customers.Count - 1) current++; }
public override void PriorRecord() { if (current > 0) current--; }
public override void NewRecord(string name) { customers.Add(name); }
public override void DeleteRecord(string name) { customers.Remove(name); }
public override void ShowRecord() { Console.WriteLine(customers[current]); }
public override void ShowAllRecords() {
foreach (string name in customers) Console.WriteLine(" " + name);
}
}
// 客戶端測試
public class BusinessApp {
public static void Main(string[] args) {
CustomersBusinessObject customers = new CustomersBusinessObject("Chicago");
customers.DataObject = new CustomersDataObject();
customers.Show(); customers.Next(); customers.Show();
customers.Next(); customers.Show();
customers.New("Henry Velasquez"); customers.ShowAll();
}
}
橋接模式體現了「面向介面編程」與「組合優於繼承」的精髓,是應對多維度變化的利器。