C++設計模式-責任鏈模式詳解
責任鏈模式:使多個物件都由機會處理請求,從而避免了請求的傳送者和接受者之間的耦合關係。將所有的可以處理這個請求的物件組成一個責任鏈,使請求最終可以被執行處理。
作為一個開發人員,在開發過程中經常會遇到與客戶或者團隊成員之間的交流問題,但是作為一個底層的碼農,有很多時候寫程式碼都是身不由己,需要各種請示。比如客戶提出新的需求需要修改程式碼,需要向技術經理或者架構師提出申請,如何修改;如果客戶是功能的修改刪除又需要向專案經理提出申請;要是客戶提出新的功能需求,還需要向經理請示增加研發經費等等。
但是大家都知道,開發團隊在領到自己的任務的時候,往往都是自己悶頭苦幹,很少關注專案本身意外的問題,突然有一天客戶需要修改一個功能模組,準備向架構師提出申請的時候,架構師不在,沒法只好向專案經理提出來,但是專案經理正在忙其他的事情,沒有時間,最後只能向經理請示。不愧是最後的決策者,當場就決定按照客戶的需求來修改。
這樣的場景大家肯定會碰到過,遇到問題要首先向自己的上級來申請解決,如果自己的上級有事情,那就向更上一級來申請,一級一級的申請,在中國不可以越級申請的這可是犯了大忌滴(呵呵),最後沒有辦法只能向經理也就是最大的上級申請,反正無論如何自己的請求一定要得到答覆。
這就是責任鏈,提出的需求最後肯定會在這條鏈中得到相應的處理。那麼如何通過程式碼來實現這一個過程呢?
1.首先定義請求的類別:
enum MemberLevel {
MEMBER_CODE,//程式碼級別
MEMBER_PROJECT,//專案級別
MEMBER_BUSINESS,//商務級別
};
2.定義請求的物件,並且給每個請求的物件分配一定的類別:
//請求的內容
class RequestMsg {
public:
RequestMsg(MemberLevel level);
~RequestMsg();
MemberLevel getMemberLevel();
void setMsg(std::string msg);
std::string getMsg();
void setMsgID(int id);
int getMsgID();
private:
MemberLevel _level;
std::string _msg;
int _msgID = 0;
};
RequestMsg::RequestMsg(MemberLevel level) { _level = level; } RequestMsg::~RequestMsg() { } MemberLevel RequestMsg::getMemberLevel() { return _level; } void RequestMsg::setMsg(std::string msg) { _msg = msg; } std::string RequestMsg::getMsg() { return _msg; } void RequestMsg::setMsgID(int id) { _msgID = id; } int RequestMsg::getMsgID() { return _msgID; }
3.定義接收請求的物件的基類:
class IHandler {
public:
IHandler();
~IHandler();
virtual void process(RequestMsg* request);
virtual void handleMsg(RequestMsg* request);
void setNextHandler(IHandler* nextHandler);
protected:
IHandler* _nextHandler = nullptr;//下一個處理者
MemberLevel _handleLevel;//處理事物的級別
};
IHandler::IHandler() {
}
IHandler::~IHandler() {
}
void IHandler::process(RequestMsg* request) {
if (_handleLevel == request->getMemberLevel()) {
handleMsg(request);
} else {
_nextHandler->process(request);
}
}
void IHandler::handleMsg(RequestMsg* request) {
}
void IHandler::setNextHandler(IHandler* nextHandler) {
_nextHandler = nextHandler;
}
這裡面有兩個函式:
void setNextHandler(IHandler* nextHandler);
設定下一個處理請求的物件。
virtual void process(RequestMsg* request);
這個函式就是定義了處理的過程,如果請求的級別和當前處理的級別是一樣就處理當前的請求,如果處理級別不一致就傳遞給下一個處理者。
virtual void handleMsg(RequestMsg* request);
每一個繼承自這個類的子類都必須實現這個函式,這個函式才是真正處理請求的函式。這個函式實際使用模板的設計模式,把演算法結構定義好,子類只需要實現這個函式就可以了。
4.定義處理的子類
第一個子類:程式碼級別的處理
//程式碼級別的處理
class CoderHandle : public IHandler {
public:
CoderHandle();
void handleMsg(RequestMsg* request)override;
};
CoderHandle::CoderHandle() {
_handleLevel = MEMBER_CODE;
}
void CoderHandle::handleMsg(RequestMsg* request) {
printf("軟體架構師處理程式碼的修改!MSGID:%d 訊息:%s\n", request->getMsgID(), request->getMsg().c_str());
}
第二個子類:專案級別的處理
//專案級別的處理
class ProjectHandle :public IHandler {
public:
ProjectHandle();
void handleMsg(RequestMsg* request)override;
};
ProjectHandle::ProjectHandle() {
_handleLevel = MEMBER_PROJECT;
}
void ProjectHandle::handleMsg(RequestMsg* request) {
printf("專案經理處理專案的需求!MSGID:%d 訊息:%s\n", request->getMsgID(), request->getMsg().c_str());
}
第三個子類:商務級別的處理
//商務級別的處理
class BusinessHandle :public IHandler {
public:
BusinessHandle();
void handleMsg(RequestMsg* request)override;
};
BusinessHandle::BusinessHandle() {
_handleLevel = MEMBER_BUSINESS;
}
void BusinessHandle::handleMsg(RequestMsg* request) {
printf("老闆處理商務的要求!MSGID:%d 訊息:%s\n", request->getMsgID(), request->getMsg().c_str());
}
在以上的三個子類中,他們的建構函式就定義了將要處理的請求的級別,又分別過載了處理請求的函式。
5.請求的傳送者基類
class IWorker {
public:
IWorker(std::string name);
~IWorker();
void setRequest(RequestMsg* request);
RequestMsg* getRequest();
std::string getName();
protected:
std::string _name;
RequestMsg* _request;
};
IWorker::IWorker(std::string name) {
_name = name;
}
IWorker::~IWorker() {
}
void IWorker::setRequest(RequestMsg* request) {
_request = request;
}
RequestMsg* IWorker::getRequest() {
return _request;
}
std::string IWorker::getName() {
return _name;
}
6.具體的請求傳送者
class ProjectMember :public IWorker {
public:
ProjectMember(std::string name);
};
ProjectMember::ProjectMember(std::string name)
:IWorker(name){
}
請求的傳送者只是公有繼承而已。裡面只有一個建構函式,沒有任何其他的函式,因為子類可以直接服用基類的共有方法。
7.使用場景
int main() {
//設定責任鏈
IHandler* codeHandle = new CoderHandle();
IHandler* projectHandle = new ProjectHandle();
IHandler* businessHandle = new BusinessHandle();
codeHandle->setNextHandler(projectHandle);
projectHandle->setNextHandler(businessHandle);
//專案成員-小明
ProjectMember* xiaoming = new ProjectMember("小明");
//小明的請求
RequestMsg* xmRequest = new RequestMsg(MEMBER_CODE);
xmRequest->setMsgID(1);
xmRequest->setMsg("程式碼結構混亂,需要重構一下程式碼結構!");
xiaoming->setRequest(xmRequest);
codeHandle->process(xmRequest);
//專案成員-小強
ProjectMember* xiaoqiang = new ProjectMember("小強");
//小強的請求
RequestMsg* xqRequest = new RequestMsg(MEMBER_BUSINESS);
xqRequest->setMsgID(2);
xqRequest->setMsg("客戶專案需要加大投入,提高預算!");
xiaoqiang->setRequest(xqRequest);
codeHandle->process(xqRequest);
//專案成員-王工
ProjectMember* wanggong = new ProjectMember("王工");
//王工的請求
RequestMsg* wgRequest = new RequestMsg(MEMBER_PROJECT);
wgRequest->setMsgID(3);
wgRequest->setMsg("客戶提出新需求!");
wanggong->setRequest(wgRequest);
codeHandle->process(wgRequest);
return 0;
}
專案組成員小明向自己的直接上級架構師申請一個程式碼級別的修改,架構師直接回復了,因為這就是架構師的許可權和職責;
專案組成員小強向自己的直接上級結構師申請了一個商務級別的請求,但是這就不是架構師的職責範圍,架構師會把請求傳遞到專案經理,但專案經理也沒有商務許可權,最後把這個請求傳遞給最後老闆,老闆做出了回覆;
專案成員王工也向自己的直接上級結構師申請了一個專案級別的請求,架構師沒有處理這個請求的許可權會把請求傳遞給專案經理,然後專案經理給出了答覆。
所有每一請求都是先向自己的直接上級發出請求,自己的上級無法處理請求時會把這個請求向下一個處理者傳遞,一直到這個請求被處理為止。
那麼這個責任鏈是如何形成的呢?是通過函式
void setNextHandler(IHandler* nextHandler);
設定的,每一個處理者都會設定自己的下一個處理者,當自己的處理不了當前級別的請求時,就會傳遞給下一個處理者。
執行結果:
責任鏈模式的優點:將請求和處理者分開,提高系統的靈活性;
但是一定要控制這個責任鏈的長度,否則會有效率的問題。責任鏈處理請求都是從開頭第一個處理者開始,直到遇到可以處理這個請求的處理者位置,如果責任鏈很長的話,每次處理請求會重複以上的過程,整體的效率會降低。