假設市面有 多品牌電視(RCA、Sony、TCL...)與 多廠商遙控器(基本款、語音款、觸控款...)。傳統聚合方案:每種遙控器內部聚合一種電視接口,需為每種組合寫一個具體類(RCA基本遙控器、Sony語音遙控器...),類數量 = 遙控器種類 × 電視品牌,新增任意一方都引發類爆炸,維護成本極高。
將抽象部分與實現部分分離,使它們可以獨立地變化。 —— GoF
關鍵設計決策:為什麼 TV 接口聚合在 抽象類 RemoteControl 中,而非具體子類?
因為只有放在抽象層,所有遙控器子類自動獲得對所有電視品牌的支持,新增電視品牌零修改遙控器代碼;若放在子類,遙控器維度擴展時仍需重複聚合邏輯,違背橋接初衷。
// 實現層接口:電視機
public interface TV {
void on();
void off();
void tuneChannel(int channel);
}
// 具體實現:RCA 電視
public class RCA implements TV {
@Override public void on() { System.out.println("RCA 開機"); }
@Override public void off() { System.out.println("RCA 關機"); }
@Override public void tuneChannel(int ch) { System.out.println("RCA 切換到 " + ch + " 台"); }
}
// 具體實現:Sony 電視
public class Sony implements TV { ... }
// 抽象層:遙控器(持有 TV 引用)
public abstract class RemoteControl {
protected TV tv;
public RemoteControl(TV tv) { this.tv = tv; }
public abstract void on();
public abstract void off();
public void setChannel(int ch) { if (tv != null) tv.tuneChannel(ch); }
}
// 擴展抽象:具體遙控器(增加換台邏輯)
public class ConcreteRemote extends RemoteControl {
private int current = 0;
private static final int MAX = 25;
public ConcreteRemote(TV tv) { super(tv); }
@Override public void on() { tv.on(); }
@Override public void off() { tv.off(); }
@Override public void setChannel(int ch) { current = ch; super.setChannel(current); }
public void nextChannel() { current = (MAX + current + 1) % MAX; super.setChannel(current); }
public void prevChannel() { current = (MAX + current - 1) % MAX; super.setChannel(current); }
}
// 客戶端:任意組合
public class Client {
public static void main(String[] args) {
TV rca = new RCA();
TV sony = new Sony();
RemoteControl rc1 = new ConcreteRemote(rca);
RemoteControl rc2 = new ConcreteRemote(sony);
rc1.on(); rc1.setChannel(5); rc1.nextChannel();
rc2.on(); rc2.setChannel(8); rc2.prevChannel();
}
}
| 優點 | 缺點 |
|---|---|
| 抽象與實現解耦,雙方獨立擴展,符合開閉原則 | 增加系統理解難度,需識別兩個獨立變化維度 |
| 避免繼承導致的類爆炸,組合優於繼承 | 雙層間接調用,極微量性能開銷(可忽略) |
| 對客戶端屏蔽實現細節,提高靈活性 | 不適用於單一固定實現的簡單場景 |
Driver(抽象)+ 各廠商 Connection/Statement(實現),應用無感切換數據庫。List(抽象)+ ArrayList/LinkedList(實現),算法針對接口編程。Window(抽象)+ WindowsImpl/MacImpl(實現),Java AWT/SWT 採用此思想。Notifier(抽象:郵件/短信/推送)+ Provider(實現:SMTP/Twilio/APNs)。橋接模式適用於 「抽象有多種變化、實現也有多種變化、且兩者需任意組合」 的場景。設計時問自己:
1. 系統中是否存在兩個正交變化維度?
2. 是否預期它們未來會獨立擴展?
3. 能否定義穩定的實現接口?
若答案全是 YES,果斷引入橋接,用組合替代繼承,賦予系統優雅的演化能力。