iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
Software Development

深入淺出設計模式 - 使用 C++系列 第 20

[Day 20] 將實作與抽象放在不同類別階層 — 橋接器模式 (Bridge Pattern)

  • 分享至 

  • xImage
  •  

說明

  • Bridge is a structural design pattern that lets you split a large class or a set of closely related classes into two separate hierarchies — abstraction and implementation
  • You can prevent the explosion of a class hierarchy by transforming it into several related hierarchies
    • Bridge Pattern 可以用合成代替繼承關係,進而降低抽象和實作的耦合

Why use Bridge?

問題

https://ithelp.ithome.com.tw/upload/images/20231002/20138643CNbw8A063u.png

  • 如果你有一個幾何形狀 (Shape) 類別,並有一對子類別: 圓形 (Circle) 和正方形 (Square)
  • 你想要擴展類別階層以包含顏色,因此你計劃創建 Red 和 Blue 的形狀子類別
  • 然而,由於你已經有兩個子類別,你將需要創建四種類別組合
    • 例如: BlueCircle、RedCircle 和 BlueSquare、RedSquare
  • 向階層中添加新的形狀類型和顏色將會使子類別數量呈指數型增長
    • 例如: 要添加一個三角形 (Triangle) 形狀,你需要引入兩個子類別,每種顏色一個
    • 在那之後,添加一個新的顏色將需要創建三個子類別,每種形狀類型一個

解析

  • 這個問題發生是因為我們試圖在兩個獨立的維度上擴展形狀類別: 形狀和顏色。這是繼承中一個非常常見的問題

  • 接下來,we can extract the color-related code into its own class with two subclasses: Red and Blue

  • The Shape class then gets a reference field pointing to one of the color objects

  • That reference will act as a bridge between the Shape and Color classes

    • From now on, adding new colors won’t require changing the shape hierarchy
    • https://ithelp.ithome.com.tw/upload/images/20231002/201386437ox46RjEBU.png
  • 結語

    • Use the Bridge pattern when you want to divide and organize a monolithic class that has several variants of some functionality
    • Use the pattern when you need to extend a class in several orthogonal (independent) dimensions
    • Use the Bridge if you need to be able to switch implementations at runtime

組成

Abstraction: 定義抽象類的接口
RefinedAbstraction: 擴展Abstraction中的接口
Implementor: 定義實作類的接口
ConcreteImplementor: 實作Implementor接口
https://ithelp.ithome.com.tw/upload/images/20231002/20138643q2XopfxOXc.png

範例

/**
 * 實作(Implementation)定義了所有實作類別的接口
 * 它不必與抽象(Abstraction)的接口相匹配。事實上,這兩個接口可以完全不同
 * 通常,實作接口僅提供原始操作,而抽象則基於這些原始操作定義更高級的操作
 */
class Implementation {
  virtual ~Implementation() {}
  virtual std::string OperationImplementation() const = 0;
};

/**
 * 每個具體實作(Concrete Implementation)對應於一個特定平台
 * 並使用該平台的API實現實作接口
 */
class ConcreteImplementationA : public Implementation {
 public:
  std::string OperationImplementation() const override {
    return "ConcreteImplementationA: Here's the result on the platform A.\n";
  }
};
class ConcreteImplementationB : public Implementation {
 public:
  std::string OperationImplementation() const override {
    return "ConcreteImplementationB: Here's the result on the platform B.\n";
  }
};

/**
 * 抽象(Abstraction)定義了兩個類別階層中"控制"部分的接口
 * 它維護一個實作階層對象的引用,並將所有實際工作委派給這個對象
 */
class Abstraction {
 protected:
  Implementation* implementation_;

 public:
  Abstraction(Implementation* implementation) : implementation_(implementation) {
  }

  virtual ~Abstraction() {
  }

  virtual std::string Operation() const {
    return "Abstraction: Base operation with:\n" +
           this->implementation_->OperationImplementation();
  }
};

/**
 * 你可以擴展抽象,而不改變實作類別
 */
class ExtendedAbstraction : public Abstraction {
 public:
  ExtendedAbstraction(Implementation* implementation) : Abstraction(implementation) {
  }
  std::string Operation() const override {
    return "ExtendedAbstraction: Extended operation with:\n" +
           this->implementation_->OperationImplementation();
  }
};

/**
 * 除了初始化階段,其中一個抽象對象與特定實作對象相連接外
 * 客戶端代碼應僅依賴於抽象類別。這樣,客戶端代碼可以支持任何抽象-實作組合
 */
void ClientCode(const Abstraction& abstraction) {
  // ...
  std::cout << abstraction.Operation();
  // ...
}

/**
 * 客戶端代碼應能夠與任何預配置的抽象-實作組合一起工作
 */
int main() {
  Implementation* implementation = new ConcreteImplementationA;
  Abstraction* abstraction = new Abstraction(implementation);
  ClientCode(*abstraction);
  
  std::cout << std::endl;

  implementation = new ConcreteImplementationB;
  abstraction = new ExtendedAbstraction(implementation);
  ClientCode(*abstraction);
}

Output:

Abstraction: Base operation with:
ConcreteImplementationA: Here's the result on the platform A.

ExtendedAbstraction: Extended operation with:
ConcreteImplementationB: Here's the result on the platform B.

Reference

  1. https://refactoring.guru/design-patterns/bridge
  2. https://ianjustin39.github.io/ianlife/design-pattern/bridge-pattern/

上一篇
[Day 19] 模式動物園 — 23種模式的總結及補充
下一篇
[Day 21] 拆解複雜物件的建立 - 生成器模式 (Builder Pattern)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言