1. 程式人生 > >【設計模式】責任鏈模式

【設計模式】責任鏈模式

receive req evel 自己 缺點 結果 改革 == 引用

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方法處理請求和設置自身級別, 想想單一職責原則和迪米特法則吧, 通過融合模板方法模式, 各個實現類只要關註的自己業務邏輯就成了, 至於說什麽事要自己處理, 那就讓父類去決定好了, 也就是說父類實現了請求傳遞的功能, 子類實現請求的處理, 符合單一職責原則, 各個實現類只完成一個動作或邏輯,也就是只有一個原因引起類的改變,在使用的時候用這種方法, 好處是非常明顯的了,子類的實現非常簡單,責任鏈的建立也是非常靈活的。

責任鏈模式屏蔽了請求的處理過程,你發起一個請求到底是誰處理的,這個你不用關心,只要你把請求拋給責任鏈的第一個處理者, 最終會返回一個處理結果( 當然也可以不做任何處理), 為請求者可以不用知道到底是需要誰來處理的,這是責任鏈模式的核心,同時責任鏈模式也可以作為一種補救模式來使用。舉個簡單例子,如項目開發的時候, 需求確認是這樣的:一個請求(如銀行客戶存款的幣種),一個處理者( 只處理人民幣),但是隨著業務的發展(改革開放了嘛,還要處理美元、日元等),處理者的數量和類型都有所增, 那這時候就可以在第一個處理者後面建立一個鏈,也就是責任鏈來處理請求,如果是人民幣,好,還是第一個業務邏輯來處理;如果是美元,好,傳遞到第二個業務邏輯來處理;日元、 歐元……這些都不用在對原有的業務邏輯產生很大改變, 通過擴展實現類就可以很好
地解決這些需求變更的問題。

【設計模式】責任鏈模式