iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Software Development

輕鬆學習設計模式Design Pattern系列 第 18

Day 18 責任鏈模式 Chain of Responsibility Pattern

  • 分享至 

  • xImage
  •  

想像你在公司工作,遇到一個問題,你先向主管反映,如果主管無法解決,再往上報告給更高層級的主管,直到有人能解決問題。這就是「責任鏈模式」的核心概念。這種模式允許你把任務逐層傳遞,直到某個物件可以處理它。在軟體設計中,這可以讓系統更加靈活,避免固定的條件判斷,提升維護性。

什麼是責任鏈模式?

責任鏈模式是一種行為型設計模式,允許多個物件按順序處理請求。每個物件有機會決定是否處理請求,或者將其轉交給下一個物件。這樣一來我們可以將不同的職責模組化,讓每個物件專注於自己的職責範圍,而不用關心整個處理流程。

想像你正在玩一個熱門的多人線上遊戲。當你遇到問題需要幫助時,你可能會先詢問遊戲內的自動客服系統。如果自動客服無法解決,問題會被轉到人工客服。如果人工客服也無法處理,問題可能會被上報給技術支援團隊。這就是一個典型的責任鏈模式應用場景。

責任鏈模式在客戶支援系統中的應用

一個常見的應用例子是客戶支援系統,當客戶送出問題時,問題可能由多個不同層級的支援人員來處理:自動客服、人工客服、技術支援團隊等。每個層級都會檢查問題,如果無法解決,就會向上級遞交,直到問題被解決。

首先我們定義一個抽象的處理者類,每個處理者 Handler(如客服)都有一個處理請求的方法,

// 處理者 Handler
class CustomerServiceHandler {
protected:
    CustomerServiceHandler* nextHandler;
public:
    virtual ~CustomerServiceHandler() = default;
    virtual void setNext(CustomerServiceHandler* handler) {
        nextHandler = handler;
    }
    virtual void handleRequest(const std::string& request) = 0;
};

然後我們實現具體的處理者類,具體的 Handler 如自動客服、人工客服和技術支援團隊繼承這個介面,並實現處理方法,

// 具體處理者 Concrete Handlers
class AutomatedSystem : public CustomerServiceHandler {
public:
    void handleRequest(const std::string& request) override {
        if (request == "簡單問題") {
            std::cout << "自動系統:我可以回答這個簡單問題。" << std::endl;
        } else if (nextHandler != nullptr) {
            nextHandler->handleRequest(request);
        }
    }
};

class HumanAgent : public CustomerServiceHandler {
public:
    void handleRequest(const std::string& request) override {
        if (request == "複雜問題") {
            std::cout << "人工客服:我來處理這個複雜問題。" << std::endl;
        } else if (nextHandler != nullptr) {
            nextHandler->handleRequest(request);
        }
    }
};

class TechnicalSupport : public CustomerServiceHandler {
public:
    void handleRequest(const std::string& request) override {
        if (request == "技術問題") {
            std::cout << "技術支援團隊:我們會深入研究並解決這個問題。" << std::endl;
        } else if (nextHandler != nullptr) {
            nextHandler->handleRequest(request);
        } else {
            std::cout << "無法解決這個問題。" << std::endl;
        }
    }
};

最後客戶端可以這樣使用,當客戶發出請求時,系統會從自動客服開始,如果無法處理,請求會傳遞到下一個層級,直到問題解決,

int main() {
    // 建立三個處理者
    AutomatedSystem* autoSystem = new AutomatedSystem();
    HumanAgent* humanAgent = new HumanAgent();
    TechnicalSupport* techSupport = new TechnicalSupport();

    // 設定責任鏈
    autoSystem->setNext(humanAgent);
    humanAgent->setNext(techSupport);

    // 測試不同請求
    autoSystem->handleRequest("簡單問題");
    autoSystem->handleRequest("複雜問題");
    autoSystem->handleRequest("技術問題");

    delete autoSystem;
    delete humanAgent;
    delete techSupport;

    return 0;
}

執行上述程式碼,我們會得到以下輸出:

自動系統:我可以回答這個簡單問題。
人工客服:我來處理這個複雜問題。
技術支援團隊:我們會深入研究並解決這個問題。

責任鏈模式的優缺點

責任鏈模式的一大優點是它讓系統更加靈活。新增一個處理者 Handler 不需要修改其他 Handler 的程式碼,只需要在責任鏈中插入新的 Handler 即可,這極大地提高了擴展性。同時 Handler 之間的耦合度降低,每個 Handler 只專注於自己能解決的問題。

然而這個模式也有一些的缺點。如果責任鏈過長請求可能會經過很多 Handler,增加了系統的處理時間。此外如果沒有適當的終止條件,請求可能會在處理鏈中無限傳遞。

總結

責任鏈模式讓我們能夠將職責分散到不同的處理者 Handler 中,提升了系統的可擴展性和維護性。在某些需要多層處理的場景,像是客戶支援系統或是事件處理系統中,這是一種非常有效的解決方案。這個模式避免了一堆 if-else 的條件判斷,讓系統更靈活但也需要注意過長的處理鏈條可能帶來的效率問題。

更多C++語言相關的文章,歡迎追蹤我的部落格。
https://shengyu7697.github.io/cpp-chain-of-responsibility-pattern/


上一篇
Day 17 備忘錄模式 Memento Pattern
系列文
輕鬆學習設計模式Design Pattern18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言