各司其職的物件串成一鏈,依照此鏈傳遞並處理請求。
設計模式是解決開發時遇到普遍存在(反覆出現)的問題的各種解法。但並不是絕對的,遇到問題才使用解法而不是為了使用而使用。
切記: 不要拿了錘子,看什麼都是釘子
介紹
職責鏈屬於行為型模式,在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。
組成
- Handler: 定義一個處理請求的接口,包含抽象處理方法及後續方法。
- ConcreteHandler: 實作Handler的處理方法,判斷是否可以處理這次的請求,可以則處理,不行則往後傳。
情境
一般來說,一間公司核准請假天數的權限會因為職階而有所差異。像是主管的上限是七天,經理是十五天。超過十五天則需要老闆批准。
當有員工要請十天假,組長無法核准這個假別,就會再往下一層提交。這就是責任鏈模式。
範例
抽象處理層
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| # 抽象處理者 abstract class Leader { protected $next; protected String $name;
public function setNext(Leader $next) { $this->next = $next; }
public function getLeader(): Leader { return $this->next; }
public function leaveSuccessed(int $days) { echo $this->name . '已批准你申請 ' . $days . ' 天假期!'; }
public function leaveFailed() { echo '請假天數太高,無可核准權限主管!'; }
abstract public function handleRequest(int $days); }
|
各職階長官
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| # 組長(7天) class Director extends Leader { protected String $name = '主管';
public function handleRequest(int $days) { if ($days <= 7) { $this->leaveSuccessed($days); } else { if ($this->next) { $this->next->handleRequest($days); } else { $this->leaveFailed();
} } } }
# 經理(15天) class Manager extends Leader { protected String $name = '經理';
public function handleRequest(int $days) { if ($days <= 15) { $this->leaveSuccessed($days); } else { if ($this->next) { $this->next->handleRequest($days); } else { $this->leaveFailed(); } } } }
# 老闆 class Boss extends Leader { protected String $name = '老闆';
public function handleRequest(int $days) { $this->leaveSuccessed($days); } }
|
組裝鏈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class LeaveApproval { public function main(int $days) { # 組長 $director = new Director();
# 經理 $manager = new Manager();
# 老闆 $boss = new Boss();
$director->setNext($manager); $manager->setNext($boss);
$director->handleRequest($days); } }
|
員工請假
1 2 3
| $leaveApproval = new LeaveApproval(); $leaveApproval->main(30); exit;
|
結果
也可以將鍊理到老闆移掉(老闆不在家),會得到結果
討論
責任鏈模式中有兩個行為,一個是承擔責任,另一個則是把責任往下推。承擔責任又可分為全責承擔與部分承擔,部分承擔允許只承擔部分責任,將其餘的責任往下推的情況,而且一個請求可以最終不被任何接收端對象所接收。
職責鏈模式的定義讓多個物件都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。