【設計模式】責任鏈模式
1、定義
1.1 標準定義
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.(使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關系。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有對象處理它為止。)
1.2 通用類圖
責任鏈模式的核心在“鏈”上, “鏈”是由多個處理者ConcreteHandler組成的。
2、實現
2.1 類圖
抽象處理者(Handler)角色:定義出一個處理請求的接口。如果需要,接口可以定義出一個方法,以設定和返回對下家的引用。這個角色通常由一個抽象類或接口實現。
具體處理者(ConcreteHandler)角色:具體處理者接到請求後,可以選擇將請求處理掉,或者將請求傳給下家。由於具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。
2.2 代碼
2.2.1 Hander類
// Chander.h #include <iostream> class CResponse;class CRequest; class CHander { public: CHander(); ~CHander(); CResponse * mopHandleMessage(CRequest *opRequest); void mvSetNext(CHander *opHander); protected: virtual std::string msGetEcho() = 0; protected: CHander *mopNexthander; int miLevel; }; // 構造三個鏈成員class CHander_1 : public CHander { public: CHander_1(); ~CHander_1(); virtual std::string msGetEcho(); }; class CHander_2 : public CHander { public: CHander_2(); ~CHander_2(); virtual std::string msGetEcho(); }; class CHander_3 : public CHander { public: CHander_3(); ~CHander_3(); virtual std::string msGetEcho(); }; // 請求 class CRequest { public: int miNumber; }; // 反饋 class CResponse { public: CResponse(const std::string &sResponse); ~CResponse(); // 獲取請求處理結果 std::string msGetResponse(); private: std::string msResponse; };
// Chander.cpp #include "CHander.h" // CHander CHander::CHander() {}; CHander::~CHander(){}; CResponse *CHander::mopHandleMessage(CRequest *opRequest) { if (miLevel == opRequest->miNumber) { return new CResponse(msGetEcho()); } else { if (NULL != mopNexthander) { return mopNexthander->mopHandleMessage(opRequest); } } return new CResponse("No Handle."); } void CHander::mvSetNext(CHander *opHander) { this->mopNexthander = opHander; } // CHander_1 CHander_1::CHander_1() { // 定義級別 miLevel = 1; mopNexthander = NULL; } CHander_1::~CHander_1(){}; std::string CHander_1::msGetEcho() { return "CHander_1 message.\n"; } // CHander_2 CHander_2::CHander_2() { // 定義級別 miLevel = 2; mopNexthander = NULL; } CHander_2::~CHander_2(){}; std::string CHander_2::msGetEcho() { return "CHander_2 message.\n"; } // CHander_3 CHander_3::CHander_3() { // 定義級別 miLevel = 3; mopNexthander = NULL; } CHander_3::~CHander_3(){}; std::string CHander_3::msGetEcho() { return "CHander_3 message.\n"; } //CResponse CResponse::CResponse(const std::string &sResponse) : msResponse(sResponse){} CResponse::~CResponse(){}; std::string CResponse::msGetResponse() { return msResponse; }
2.2.3 調用
#include <iostream> #include "CHander.h" using namespace std; int main() { CHander *opHander1 = new CHander_1; CHander *opHander2 = new CHander_2; CHander *opHander3 = new CHander_3; //構造執行鏈 opHander1->mvSetNext(opHander2); opHander2->mvSetNext(opHander3); CRequest *opRequest = new CRequest; opRequest->miNumber = 2; CResponse *opResponse = opHander1->mopHandleMessage(opRequest); std::cout << opResponse->msGetResponse().c_str() << endl; delete opResponse; opResponse = NULL; opRequest->miNumber = 1; opResponse = opHander1->mopHandleMessage(opRequest); std::cout << opResponse->msGetResponse().c_str() << endl; delete opResponse; opResponse = NULL; opRequest->miNumber = 4; opResponse = opHander1->mopHandleMessage(opRequest); std::cout << opResponse->msGetResponse().c_str() << endl; delete opResponse; opResponse = NULL; delete opHander1; delete opHander2; delete opHander3; return 0; }
2.2.3 執行結果
3、優缺點
3.1 優點
責任鏈模式非常顯著的優點是將請求和處理分開。請求者可以不用知道是誰處理的,處理者可以不用知道請求的全貌。兩者解耦,提高系統的靈活性。
3.2 缺點
責任鏈有兩個非常顯著的缺點:一是性能問題,每個請求都是從鏈頭遍歷到鏈尾,特別是在鏈比較長的時候,性能是一個非常大的問題。二是調試不很方便,特別是鏈條比較長,環節比較多的時候,由於采用了類似遞歸的方式,調試的時候邏輯可能比較復雜。
3.3 註意
鏈中節點數量需要控制,避免出現超長鏈的情況,一般的做法是在Handler中設置一個最大節點數量,在setNext方法中判斷是否已經是超過其閾值,超過則不允許該鏈建立,避免無意識地破壞系統性能。
3.4 總結
在例子和通用源碼中CHandler是抽象類, 融合了模板方法模式, 每個實現類只要實現 echo方法處理請求和設置自身級別, 想想單一職責原則和迪米特法則吧, 通過融合模板方法模式, 各個實現類只要關註的自己業務邏輯就成了, 至於說什麽事要自己處理, 那就讓父類去決定好了, 也就是說父類實現了請求傳遞的功能, 子類實現請求的處理, 符合單一職責原則, 各個實現類只完成一個動作或邏輯,也就是只有一個原因引起類的改變,在使用的時候用這種方法, 好處是非常明顯的了,子類的實現非常簡單,責任鏈的建立也是非常靈活的。
責任鏈模式屏蔽了請求的處理過程,你發起一個請求到底是誰處理的,這個你不用關心,只要你把請求拋給責任鏈的第一個處理者, 最終會返回一個處理結果( 當然也可以不做任何處理), 為請求者可以不用知道到底是需要誰來處理的,這是責任鏈模式的核心,同時責任鏈模式也可以作為一種補救模式來使用。舉個簡單例子,如項目開發的時候, 需求確認是這樣的:一個請求(如銀行客戶存款的幣種),一個處理者( 只處理人民幣),但是隨著業務的發展(改革開放了嘛,還要處理美元、日元等),處理者的數量和類型都有所增, 那這時候就可以在第一個處理者後面建立一個鏈,也就是責任鏈來處理請求,如果是人民幣,好,還是第一個業務邏輯來處理;如果是美元,好,傳遞到第二個業務邏輯來處理;日元、 歐元……這些都不用在對原有的業務邏輯產生很大改變, 通過擴展實現類就可以很好
地解決這些需求變更的問題。
【設計模式】責任鏈模式