iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0
Software Development

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

[Day 10] 物件導向轉接器 - 轉接器模式 (Adapter Pattern)

  • 分享至 

  • xImage
  •  

轉接器模式 (Adapter Pattern)

  • Adapter Pattern 是一種結構型設計模式,旨在允許兩個不相容的接口能夠協同工作

  • 組成:

    1. Target(目標接口)
      • 這是客戶端所期望的接口
      • 客戶端透過這個接口與功能進行互動
    2. Adaptee(被適配者或待適配的接口)
      • 這是原有的、未經適配的接口,其功能需要被利用
      • 它的方法和目標接口的方法可能不相容,這也是為什麼需要一個適配器來進行轉換的原因
    3. Adapter(適配器)
      • 適配器實作目標接口,同時持有被適配者的一個實例
      • 適配器將目標接口的呼叫轉換為待適配的接口的呼叫
      • 它“轉換”或“翻譯”客戶端的請求,使得被適配者能夠理解和處理這些請求
  • 流程: Client <-> Target (Interface) <-> Adapter <-> Adaptee
    https://ithelp.ithome.com.tw/upload/images/20230922/2013864381J1ZpZm3o.jpg

    1. 適配器接收到目標接口的呼叫
    2. 將這些呼叫轉換為待適配的接口上的呼叫
  • 分析:

    • 優點:
      • 即使既有的類不符合新的系統或模組的需求,也能夠透過適配器重用它 (例如,更換 Library)
      • 能夠獨立地修改或增加待適配的接口和適配器,而不影響其他部分 (可靈活維護)
      • 用戶端不需要知道適配器的存在,它只與目標接口互動
    • 缺點:
      • 增加了系統的複雜性,為了使接口相容,可能需要新增多個適配器類別
  • 應用場景:

    • 整合舊系統到新系統:當你想要在新系統中使用舊系統的功能,但兩者接口不相容時
    • 第三方 Library 整合,當你使用的第三方庫的接口和你的系統不相容時,可以使用適配器
    • 可插拔設計,可以在運行時動態更換適配器,提供不同的功能

筆記

  • 轉接器可以將一個 Interface 轉換成另一個 Interface (類似電器的轉接器),以滿足用戶端的需求
  • Client 端與 Adaptee 是不耦合的,互不認識
  • 製作轉接器的工作量與目標介面的大小成正比

範例

// 目標接口 (Target)
class Target {
public:
    virtual void request() = 0;
};

// 待適配的接口 (Adaptee)
class Adaptee {
public:
    void specificRequest() {
        // 這是原本的方法,與目標接口不相容
        cout << "Called Specific Request!" << endl;
    }
};

// 適配器 (Adapter)
class Adapter : public Target {
private:
    Adaptee* adaptee;  // 持有一個待適配的接口的實例

public:
    Adapter(Adaptee* a) : adaptee(a) {}

    // 實作目標接口的請求方法
    void request() override {
        // 轉換呼叫為待適配的接口的呼叫
        adaptee->specificRequest();
    }
};

int main() {
    // 創建被適配者
    Adaptee* adaptee = new Adaptee();
    
    // 透過適配器使其與目標接口相容
    Target* target = new Adapter(adaptee);
    
    // 客戶端僅與目標接口互動
    target->request();  // 輸出: Called Specific Request!
}

[補充]: Two Way Adapter

  • 是 Adapter Pattern 的一個變種,它不僅允許目標接口(Target)使用被適配的接口(Adaptee),還允許被適配的接口使用目標接口。換句話說,雙向適配器允許雙方相互通信
  • 能夠輕鬆地在兩個不同的接口之間進行互動,而無需擔心接口不兼容的問題 (更靈活,但也更複雜)

虛擬碼

class Target {
    virtual void targetRequest() = 0
}

class Adaptee {
    void specificRequest() {
        // specific behavior
    }
}

class TwoWayAdapter : public Target {
private:
    Target* targetInstance;
    Adaptee* adapteeInstance;

public:
    TwoWayAdapter(Target* t, Adaptee* a): targetInstance(t), adapteeInstance(a) {}

    // Target 向 Adaptee 溝通
    void targetRequest() override {
        adapteeInstance->specificRequest();
    }

    // Adaptee 向 Target 溝通
    void adaptSpecificRequest() {
        targetInstance->targetRequest();
    }
}

// 主程式範例:
Target* concreteTarget = new ConcreteTarget();
Adaptee* adaptee = new Adaptee();

TwoWayAdapter* adapter = new TwoWayAdapter(concreteTarget, adaptee);

adapter->targetRequest();        // Calls Adaptee's specificRequest method
adapter->adaptSpecificRequest(); // Calls ConcreteTarget's targetRequest method

Reference

[1]. https://www.geeksforgeeks.org/adapter-pattern/


上一篇
[Day 09] 將方法的呼叫封裝起來 - 命令模式 ( Command Pattern )
下一篇
[Day 11] 讓介面更簡單 – 門面模式 (Facade Pattern)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言