Hi 👋 ~ 今天來跟大家聊聊責任鏈設計模式 (Chain of Responsibility Design Pattern)!
責任鏈設計模式是什麼?
- 責任鏈模式是一種行爲設計模式。
- 針對一個處理的請求,在一連串由不同節點組成的流程中,每一個節點可以決定是否進行處理、傳遞給下一個節點或判斷不需要往下處理而駁回請求。
沒有使用責任鏈模式會怎麼樣嗎?🤯
我想大家都有去面試過的經驗,不少公司的面試流程很多都需要有 3–4 次面試 🥲
我們這次就用面試流程來看看如何使用責任鏈模式吧!
背景設定
JC KeyCode 是一家新創公司,它需要應徵「軟體工程師」與「設計師」。
針對「軟體工程師」的面試流程是:
- HR 電話初步面試
- 線上技術解題面試
- 到公司與 CTO 技術解題面試
- 到公司與 CEO 的 1 on 1 面試
針對「設計師」的面試流程是:
- HR 電話初步面試
- 到公司與設計總監進行設計作品集面試
- 到公司與 CEO 的 1 on 1 面試
沒有使用責任鏈設計模式的程式碼
我們會先有應徵者的 class:
const POSITION_TYPE_ENGINEER = 'enginner';
const POSITION_TYPE_DESIGNER = 'designer';
class Interviewee
{
public string $name;
public string $position;
public int $performance;
public function __construct(string $name, string $position, int $performance)
{
$this->name = $name;
$this->position = $position;
$this->performance = $performance;
}
}
然後就是 JcKeyCode 這家公司的 class:
class JcKeyCode
{
public function interview(Interviewee $interviewee): bool
{
// Todo:面試流程 ...
}
public function hire(Interviewee $interviewee)
{
$position = $interviewee->position == POSITION_TYPE_ENGINEER ? "工程師" : "設計師";
echo "{$interviewee->name} - {$position} 面試流程開始: ==================== " . PHP_EOL;
$result = $this->interview($interviewee);
if ($result) {
$message = "get the offer ! 🎉";
} else {
$message = "interview failed 😭";
}
echo "{$interviewee->name} - {$position} 面試流程結束: {$message} ==================== " . PHP_EOL;
echo "" . PHP_EOL;
}
}
接下來實作 interview
這個 method 的內容:
public function interview(Interviewee $interviewee): bool
{
echo "HR 電話初步面試: Start" . PHP_EOL;
// HR 電話初步面試
if ($interviewee->performance > 5) {
echo "HR 電話初步面試: Pass" . PHP_EOL;
// if Engineer
if ($interviewee->position == POSITION_TYPE_ENGINEER) {
// 線上技術解題面試
echo "線上技術解題面試: Start" . PHP_EOL;
if ($interviewee->performance > 30) {
echo "線上技術解題面試: Pass" . PHP_EOL;
// 到公司與 CTO 技術解題面試
echo "到公司與 CTO 技術解題面試: Start" . PHP_EOL;
if ($interviewee->performance > 70) {
echo "到公司與 CTO 技術解題面試: Pass" . PHP_EOL;
// 到公司與 CEO 的 1 on 1 面試
echo "到公司與 CEO 的 1 on 1 面試: Start" . PHP_EOL;
if ($interviewee->performance > 90) {
echo "到公司與 CEO 的 1 on 1 面試: Pass" . PHP_EOL;
return true;
} else {
echo "到公司與 CEO 的 1 on 1 面試: Failed" . PHP_EOL;
return false;
}
} else {
echo "到公司與 CTO 技術解題面試: Failed" . PHP_EOL;
return false;
}
} else {
echo "線上技術解題面試: Failed" . PHP_EOL;
return false;
}
}
// if Designer
if ($interviewee->position == POSITION_TYPE_DESIGNER) {
// 到公司與設計總監進行設計作品集面試
echo "到公司與設計總監進行設計作品集面試: Start" . PHP_EOL;
if ($interviewee->performance > 80) {
echo "到公司與設計總監進行設計作品集面試: Pass" . PHP_EOL;
// 到公司與 CEO 的 1 on 1 面試
echo "到公司與 CEO 的 1 on 1 面試: Start" . PHP_EOL;
if ($interviewee->performance > 90) {
echo "到公司與 CEO 的 1 on 1 面試: Pass" . PHP_EOL;
return true;
} else {
echo "到公司與 CEO 的 1 on 1 面試: Failed" . PHP_EOL;
return false;
}
} else {
echo "到公司與設計總監進行設計作品集面試: Failed" . PHP_EOL;
return false;
}
}
} else {
echo "HR 電話初步面試: Failed" . PHP_EOL;
return false;
}
}
最後使用的程式碼:
function main()
{
$jcKeyCode = new JcKeyCode();
// deisgner
$john = new Interviewee("John", POSITION_TYPE_DESIGNER, 3);
$jcKeyCode->hire($john);
$alice = new Interviewee("Alice", POSITION_TYPE_DESIGNER, 15);
$jcKeyCode->hire($alice);
$paul = new Interviewee("Paul", POSITION_TYPE_DESIGNER, 85);
$jcKeyCode->hire($paul);
$patty = new Interviewee("Patty", POSITION_TYPE_DESIGNER, 95);
$jcKeyCode->hire($patty);
// engineer
$mary = new Interviewee("Mary", POSITION_TYPE_ENGINEER, 4);
$jcKeyCode->hire($mary);
$tommy = new Interviewee("Tommy", POSITION_TYPE_ENGINEER, 15);
$jcKeyCode->hire($tommy);
$peter = new Interviewee("Peter", POSITION_TYPE_ENGINEER, 80);
$jcKeyCode->hire($peter);
$david = new Interviewee("David", POSITION_TYPE_ENGINEER, 99);
$jcKeyCode->hire($david);
}
main();
🤯 上述程式碼的問題:
- 在
interveiw()
裏面if
跟else
的複雜的判斷邏輯混雜在一起 - 在
interveiw()
裏面的判斷式無法共用,例如engineer
跟designer
最後都需要經過 CEO 的面試,但卻要因爲不同的狀況要分別寫在兩處 - 在
interveiw()
裏面已經這麼混亂的情況下,如果要再新增一個HR
的職位面試判斷,想必是一場災難。。。 🤯
例如: HR 只需要給 CEO 面試過關即可。
public function interview(Interviewee $interviewee): bool
{
echo "HR 電話初步面試: Start" . PHP_EOL;
// HR 電話初步面試
if ($interviewee->performance > 5) {
echo "HR 電話初步面試: Pass" . PHP_EOL;
// if Engineer
if ($interviewee->position == POSITION_TYPE_ENGINEER) {
// 工程師的面試流程 ... 略
}
// if Designer
if ($interviewee->position == POSITION_TYPE_DESIGNER) {
// 設計師的面試流程 ... 略
}
// if HR
if ($interviewee->position == POSITION_TYPE_HR) {
// 到公司與 CEO 的 1 on 1 面試
echo "到公司與 CEO 的 1 on 1 面試: Start" . PHP_EOL;
if ($interviewee->performance > 90) {
echo "到公司與 CEO 的 1 on 1 面試: Pass" . PHP_EOL;
return true;
} else {
echo "到公司與 CEO 的 1 on 1 面試: Failed" . PHP_EOL;
return false;
}
}
} else {
echo "HR 電話初步面試: Failed" . PHP_EOL;
return false;
}
}
相信你看到上述的實作應該覺得有點不妙。。。 🥲
那些接下來我們前往 圈圈工程師 就來看看如何使用責任鏈設計模式改善上述的程式碼吧!