責任鏈模式( Chain of Responsibility Pattern): 為請求創建了一個接收者對象的鏈,并沿這條鏈傳遞該請求,直到有對象處理它為止。這種模式能夠給予請求的類型,對請求的發送者和接收者進行解耦。
(一)為什么需要責任鏈模式
1,將請求的發送者和請求的處理者解耦了。責任鏈上的處理者負責處理請求,客戶只需要將請求發送到職責鏈上即可,無須關心請求的處理細節和請求的傳遞。
2, 發出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任
(二)責任鏈模式 UML圖
Chain of Responsibility Pattern
(三)簡單實例
如果我們現在做一個員工系統,如果說公司有規定說員工有請示,要根據請示的級別由不同人批示。比如請假由組長批示,休假由主管批示,辭職由總經理批示。好了,如果我們使用代碼如何實現呢?員工類,組長類,主管類,總經理類。那么員工對象的請示直接交給總經理嗎,顯然是不好。如果我們按照現實世界的邏輯來實現,那應該是怎樣的呢?(我很贊同一句話:任何代碼的邏輯都在現實世界能找到與之對應的場景,如果沒有,就是你的邏輯有問題
)
<?php
//抽象處理者
abstract class Handler{
private $next_handler ;//存放下一處理對象
private $lever = 0; //處理級別默認0
abstract protected function response(); //處理者回應
//設置處理級別
public function setHandlerLevel($lever){
$this->lever = $lever ;
}
//設置下一個處理者是誰
public function setNext(Handler $handler){
$this->next_handler = $handler;
$this->next_handler->setHandlerLevel($this->lever+1);
}
//責任鏈實現主要方法,判斷責任是否屬于該對象,不屬于則轉發給下一級。使用final不允許重寫
final public function handlerMessage(Request $request){
if($this->lever == $request->getLever()){
$this->response();
}else{
if($this->next_handler != null){
$this->next_handler->handlerMessage($request);
}else{
echo '洗洗睡吧,沒人理你'.PHP_EOL;
}
}
}
}
//具體處理者
// headman 組長
class HeadMan extends Handler{
protected function response(){
echo '組長回復你:同意你的請求'.PHP_EOL;
}
}
//主管director
class Director extends Handler{
protected function response(){
echo '主管回復你:知道了,退下'.PHP_EOL;
}
}
//經理manager
class Manager extends Handler{
protected function response(){
echo '經理回復你:容朕思慮,再議'.PHP_EOL;
}
}
//請求類
class Request{
protected $level = array('請假'=>0,'休假'=>1,'辭職'=>2);//測試方便,默認設置好請示級別對應關系
protected $request;
public function __construct($request){
$this->request = $request;
}
public function getLever(){
//獲取請求對應的級別,如果該請求沒有對應級別 則返回-1
return array_key_exists($this->request,$this->level)?$this->level[$this->request]:-1;
}
}
//實例化處理者
$headman = new HeadMan;
$director = new Director;
$manager = new Manager;
//責任鏈組裝
$headman->setNext($director);
$director->setNext($manager);
//傳遞請求
$headman->handlerMessage(new Request('請假'));
$headman->handlerMessage(new Request('休假'));
$headman->handlerMessage(new Request('辭職'));
$headman->handlerMessage(new Request('加薪'));
具體的處理者即對應UML圖中的ConcreteHandler,請求類對應UML圖的client。使用責任鏈,可以使對應的處理者有對應的單一的response方法。請求只需交給最低級的處理者,由屬性$lever判斷,一層層傳遞到與請求級別相同的處理者中做出對應的回應。請求無需知道,要交給對應的那個處理者。
當然,當責任鏈過長時也會引起性能問題。對此我們應避免使用過長的責任鏈。