C++ 設計模式 - 責任鏈模式 Chain of Responsibility Pattern

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

什麼是責任鏈模式?

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
// 處理者 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 如自動客服、人工客服和技術支援團隊繼承這個介面,並實現處理方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 具體處理者 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;
}
}
};

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}

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

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

責任鏈模式的優缺點

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

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

總結

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