設計模式 - 職責鏈模式

各司其職的物件串成一鏈,依照此鏈傳遞並處理請求。

設計模式是解決開發時遇到普遍存在(反覆出現)的問題的各種解法。但並不是絕對的,遇到問題才使用解法而不是為了使用而使用

切記: 不要拿了錘子,看什麼都是釘子

介紹

職責鏈屬於行為型模式,在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。

組成

  • 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;

結果

1
老闆已批准你申請 30 天假期!

也可以將鍊理到老闆移掉(老闆不在家),會得到結果

1
請假天數太高,無可核准權限主管!

討論

責任鏈模式中有兩個行為,一個是承擔責任,另一個則是把責任往下推。承擔責任又可分為全責承擔部分承擔部分承擔允許只承擔部分責任,將其餘的責任往下推的情況,而且一個請求可以最終不被任何接收端對象所接收。

職責鏈模式的定義讓多個物件都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係

Author

LinYoYo

Posted on

2021-12-11

Updated on

2021-12-11

Licensed under