cover

假設你的系統有兩個變化軸:付款流程(線上、線下)和付款處理器(信用卡、PayPal、LINE Pay)。用繼承的話,2 x 3 = 6 個 class。再加一種流程?3 x 3 = 9 個。爆炸式增長。

Bridge Pattern 的解法是:把兩個維度拆開,用組合(不是繼承)連接。

先講結論

Bridge 把「抽象」和「實作」分成兩個獨立的層級,各自可以獨立發展。要加新的付款流程?加一個 class。要加新的處理器?也加一個 class。兩邊互不影響。

classDiagram
    class Payment {
        <<Abstraction>>
        -processor : PaymentProcessor
        +process(amount)* Result
    }
    class OnlinePayment {
        +process(amount) Result
    }
    class PaymentProcessor {
        <<Implementation>>
        +processPayment(amount)* Result
    }
    class CreditCardProcessor {
        +processPayment(amount) Result
    }
    Payment <|-- OnlinePayment
    PaymentProcessor <|-- CreditCardProcessor
    Payment o-- PaymentProcessor : 橋接

實戰:付款系統

Bridge 模式:抽象與實作透過橋樑自由組合

// 實作層:各種付款處理器
class CreditCardProcessor {
    async processPayment(amount) {
        console.log(`信用卡處理: $${amount}`);
        return { success: true, method: 'credit_card', amount };
    }
}
 
class LinePayProcessor {
    async processPayment(amount) {
        console.log(`LINE Pay 處理: $${amount}`);
        return { success: true, method: 'line_pay', amount };
    }
}
 
// 抽象層:付款流程
class OnlinePayment {
    constructor(processor) {
        this.processor = processor; // 橋接點
    }
    async process(amount) {
        console.log('線上付款流程啟動...');
        return await this.processor.processPayment(amount);
    }
}
 
// 自由組合:線上 + 信用卡、線上 + LINE Pay
const payment1 = new OnlinePayment(new CreditCardProcessor());
const payment2 = new OnlinePayment(new LinePayProcessor());
 
await payment1.process(100); // 線上 + 信用卡
await payment2.process(200); // 線上 + LINE Pay

新增一個 OfflinePayment?寫一個 class,跟任何 Processor 組合都行。新增一個 PayPalProcessor?也是寫一個 class,跟任何 Payment 流程組合都行。

Bridge vs Strategy

兩個都用組合,但意圖不同:

  • Bridge:解決「兩個獨立維度的排列組合」問題
  • Strategy:解決「同一個維度的演算法替換」問題

如果你只有一個維度在變化,用 Strategy。有兩個以上維度在變化,考慮 Bridge。


Bridge Pattern 就像 USB-C——手機和充電器各自發展,中間只要一個統一的接口就能連起來。問題是你的舊 Micro USB 線還有一百條


延伸閱讀