橋接模式 | Bridge Pattern

Posted by Ian Tsai on Wednesday, September 23, 2020

本系列文章同步分享於IT邦幫忙第12屆鐵人賽


Design Pattern 系列文章導讀


Design Pattern可以說是開發上大家都會遇到的一個課題, 這系列文會從Design Principles、各種design pattern到最後的Anti-Patterns & Code Smells介紹下去,讓我們可以更了解各種pattern的使用時機與場合。 預計目標主題如下,若有哪部分不熟的章節可以直接點進去看
註:可以利用Online Java Compiler IDE

  1. 設計模式 - 入門篇
  2. 設計模式 - 原則篇 | Design Principles
  3. 設計模式 - 創建型模型篇 | Creational Patterns
  4. 設計模式 - 結構型模型篇 | Structural Patterns
  5. 設計模式 - 行為型模型篇 | Behavioural Patterns
  6. 設計模式 - 番外篇
  • 定義


將抽象部分與實現部分分離,使它們都可以獨立的變化。

橋接模式(Bridge Pattern)是用合成關係代替繼承關係,進而降低抽象和實作的合度。

註:若對合成聚合原則不熟,可以點擊合成/聚合複用原則(Composite/Aggregate Reuse Principle)研究。

在現實生活中,有些類別是具有兩個維度或多個維度的變化。如不同顏色的包包。顏色跟包包就是兩個維度。

而剛剛提到合成代替繼承關係,舉一個買包包的例子。女朋友想要買LV包包,LV包包的款式又那麼多(若有人不知道,這邊貼心的給個連結XD),如果使用繼承的方式,包包種類有背包和皮包;包包的顏色有白色及黑色。我們用簡單的結構圖來看看繼承會長什麼樣子:

可以發現,一種顏色的一種包,就需要建立一個類別。類別間的耦合性相當的高,不管是要維護或是修改都非常的不容易。

  • Bridge Pattern 成員


成員 功用
Abstraction 抽象類別,定義抽象的接口,該接口包含實現具體行爲、具體特徵的Implementor接口。
RefinedAbstraction 繼承並實作Abstraction內的方法,透過合成關係呼叫Implementor內的方法。
Implementor 抽象介面,定義具體行爲、具體特徵的應用接口。
ConcreteImplementor 實作Implementor並給出接口。

Abstraction就好比包包,他裡面定義了一些方法提供RefinedAbstraction去實作,且藉由合成的方式將Implementor引入。而RefinedAbstraction就是背包或是錢包類別。Implementor則是顏色,由ConcreteImplementor實作提供真正的顏色,再經由Abstraction去呼叫使用。

我們把剛剛LV的例子帶入UML內,就會變成下圖:

Bridge Pattern 實作


剛剛看完Bridge Pattern的定義及介紹,相信都有了一些理解。現在我們把剛剛的範例寫成程式碼看看會長什麼樣子。

首先先建立Implementor並定義好其中的方法,待會讓ConcreteImplementor實作。

interface Color {
    String getColor();
}

ConcreteImplementor實作Implementor內的方法。

class White implements Color {
    public String getColor() {
        return "White";
    }
}
class Black implements Color {
    public String getColor() {
        return "Black";
    }
}

建立Abstraction類別,並將Color合成進來。

abstract class Bag {
    protected Color color;
    public void setColor(Color color) {
        this.color=color;
    }   
    public abstract String getName();
}

RefinedAbstraction繼承Abstraction,並實作其中的getName。

class Backpack extends Bag{
    public String getName() {
        return color.getColor()+"Backpack";
    }   
}

class Wallet extends Bag {
    public String getName() {
        return color.getColor()+"Wallet";
    }   
}

最後只需要把對應的物件建立組裝即可,不需要建立不同顏色的同種商品。

public class LVBag {
    public static void main(String args[]) {
        Color white = new White();
        
        Bag backpack = new Backpack();
        backpack.setColor(white);
        backpack.getName();
        
        Bag wallet = new Wallet();
        wallet.setColor(white);
        wallet.getName();
    }
}

output

White Backpack
White Wallet

藉由套用Bridge Pattern,我們解決了繼承需要產生大量類別的問題,也提升了程式整體的彈性。未來若包包種類擴充,或是顏色種類增加,只需要建立新的種類即可,不需要去影響到其他的類別。

  • 小結


Bridge Pattern的目標

將抽象部分與實現部分分離,使它們都可以獨立的變化。即用合成關係代替繼承關係。

Bridge Pattern的成員
Abstraction:抽象類別,定義抽象的接口,該接口包含實現具體行爲、具體特徵的Implementor接口。
RefinedAbstraction:繼承並實作Abstraction內的方法,透過合成關係呼叫Implementor內的方法。
Implementor:抽象介面,定義具體行爲、具體特徵的應用接口。
ConcreteImplementor:實作Implementor並給出接口。
Bridge Pattern的優缺點
優點
1. 抽象和實現的分離,提高了比繼承更好的解決方案;
2. 優秀的擴充套件能力,在兩個變化維度中任意擴充套件一個維度,都不需要修改原有系統;
3. 實現細節對客戶透明,可以對使用者隱藏實現細節。
缺點
增加系統的理解與設計難度,由於合成關聯關係建立在抽象層,要求開發者針對抽象進行設計與程式設計。
  • 範例程式碼


範例:使用Bridge Pattern

  • References


  • 桥接模式(Bridge模式)详解
  • 重走Java設計模式——橋接模式(Bridge Pattern)
  • 橋接模式