一 定義
在很多情況下,可以處理某個請求的對象不止一個,如大學裏的獎學金審批,學生在向輔導員提交審批表之後,首先是輔導員簽字審批,然後交給系主任簽字審批,接着是院長審批,最後可能是校長審批,在這個過程中,獎學金申請表可以看成是一個請求對象,而不同級別的審批者都可以處理該請求對象,除了輔導員之外,學生不需要一一和其他審批者交互,只需等待結果即可。在審批過程中如果某一個審批者任務不符合條件,則請求中止;否則將請求遞交給下一個審批者,最後由校長來確定誰能夠授予獎學金。該過程如下:
在圖中,從輔導員直到校長都可以處理申請表,而且他們構成了一條鏈,申請表沿着這條鏈傳遞,這條鏈就叫職責鏈。
職責鏈可以是一條直線,一個環或則一個樹形結構,最常見的是直線型,即沿着一條單向的鏈來傳遞請求。鏈上的每一個對象都是請求處理者,職責鏈模式可以將請求的處理者組織成一條鏈,並使請求沿着鏈傳遞,由鏈上的處理者對請求進行相應的處理,客戶端無須關心請求的處理細節以及請求的傳遞,只需將請求發送到鏈上即可,將請求的發送者和請求的處理者解耦。這就是職責鏈模式的模式動機。(客戶類只需關心鏈的源頭,而無需關心請求的處理細節及請求的傳遞過程)
定義:使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象處理它爲止。
二 ULM
角色:
抽象處理者(Handler)角色:定義出一個處理請求的接口(通常由一個Java抽象類或者Java接口實現)。如果需要,接口可以定義 出一個方法以設定和返回對下家的引用。上圖中Handler類的聚合關係給出了具體子類對下家的引用,抽象方法handleRequest()規範了子類處理請求的操作。
具體處理者(ConcreteHandler)角色:具體處理者接到請求後,可以選擇將請求處理掉,或者將請求傳給下家。由於具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。
優點
- 責任鏈模式減低了發出命令的對象和處理命令的對象之間的耦合;
- 處理者對於請求者完全透明,請求者無需事先知道誰來處理;
- 它允許多與一個的處理者對象根據自己的邏輯來決定哪一個處理者最終處理這個命令,提高系統的擴展性;
- 擴展靈活,新增具體請求者時無需修改原有系統的代碼;
缺點
- 產生許多細顆粒對象;
- 不一定能被處理,可能到末端也沒被處理或者中間寫錯;
- 比較長的責任鏈,可能涉及多個處理對象,性能問題,還有調試不方便;
- 建鏈不當,可能造成循環調用,導致系統進入死循環;
適用場景
- 多個對象可以處理同一請求,但具體由哪個對象處理,則需要動態決定時。
- 在請求者不明確的情況下需要向多個對象中的一個提交請求時。
- 需要動態的指定一組對象處理請求時。
- 系統已經有一個由處理者對象組成的鏈。這個鏈可能由複合模式給出,
- 當系統想發出一個請求給多個處理者對象中的某一個,但是不明顯指定是哪一個處理者對象會處理此請求。
- 當處理一個請求的處理者對象集合需要動態地指定時。
三 實例
請假審批:某OA系統需要提供一個假條審批的模塊,如果員工請假天數小於3天,主任可以審批該假條;如果員工請假天數大於等於3天,小於10天,經理可以審批;如果員工請假天數大於等於10天,小於30天,總經理可以審批;如果超過30天,總經理也不能審批,提示相應的拒絕信息。
ULM圖
實現代碼:
#include <iostream>
#include <string>
#include <memory>
//請求類LeaveRequest
class LeaveRequest
{
public:
LeaveRequest(std::string leaveName, int leaveDays)
{
this->leaveName = leaveName;
this->leaveDays = leaveDays;
}
void setLeaveName(std::string leaveName)
{
this->leaveName = leaveName;
}
void setLeaveDays(int leaveDays)
{
this->leaveDays = leaveDays;
}
std::string getLeaveName() const
{
return this->leaveName;
}
int getLeaveDays() const
{
return this->leaveDays;
}
private:
std::string leaveName;
int leaveDays;
};
//抽象處理者Leader
class Leader
{
public:
Leader(std::string name)
{
this->name = name;
}
void setSuccessor(std::weak_ptr<Leader> successor)
{
this->successor = successor;
}
virtual void handleRequest(const LeaveRequest& request) = 0;
protected:
std::string name;
std::weak_ptr<Leader> successor;
};
//具體處理者Director
class Director : public Leader
{
public:
Director(std::string name) : Leader(name)
{
}
void handleRequest(const LeaveRequest& request)
{
//處理請求
if (request.getLeaveDays() < 3)
{
std::cout << "主任" << this->name << "審批員工" << request.getLeaveName() << "的請假條,請假天數爲"
<< request.getLeaveDays() << "天." << std::endl;
}
else
{
//無法處理此請求,則交給上級處理
if (this->successor.lock() != nullptr)
{
this->successor.lock()->handleRequest(request);
}
}
}
};
//具體處理者Manager
class Manager : public Leader
{
public:
Manager(std::string name) : Leader(name)
{
}
void handleRequest(const LeaveRequest& request)
{
//處理請求
if (request.getLeaveDays() < 10)
{
std::cout << "經理" << this->name << "審批員工" << request.getLeaveName() << "的請假條,請假天數爲"
<< request.getLeaveDays() << "天." << std::endl;
}
else
{
//無法處理此請求,則交給上級處理
if (this->successor.lock() != nullptr)
{
this->successor.lock()->handleRequest(request);
}
}
}
};
//具體處理者GeneralManager
class GeneralManager : public Leader
{
public:
GeneralManager(std::string name) : Leader(name)
{
}
void handleRequest(const LeaveRequest& request)
{
//處理請求
if (request.getLeaveDays() < 30)
{
std::cout << "總經理" << this->name << "審批員工" << request.getLeaveName() << "的請假條,請假天數爲"
<< request.getLeaveDays() << "天." << std::endl;
}
else
{
std::cout << "莫非" << request.getLeaveName() << "想辭職,居然請假"
<< request.getLeaveDays() << "天." << std::endl;
}
}
};
//客戶端測試
int main(void)
{
std::shared_ptr<Leader> objDirector, objManager, objGeneralManager;
//創建處理者
objDirector = std::make_shared<Director>("王明");
objManager = std::make_shared<Manager>("趙強");
objGeneralManager = std::make_shared<GeneralManager>("李波");
//設置上級
objDirector->setSuccessor(objManager);
objManager->setSuccessor(objGeneralManager);
//職責鏈處理請求
auto lr1 = std::make_shared<LeaveRequest>("張三", 2);
objDirector->handleRequest(*lr1);
auto lr2 = std::make_shared<LeaveRequest>("李四", 5);
objDirector->handleRequest(*lr2);
auto lr3 = std::make_shared<LeaveRequest>("王五", 15);
objDirector->handleRequest(*lr3);
auto lr4 = std::make_shared<LeaveRequest>("趙六", 45);
objDirector->handleRequest(*lr4);
return 0;
}
運行結果: