Pattern: 命令模式
Class Diagram: 機器人廚師
情境:這是一間牛排館,會根據客戶的訂單出菜
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
namespace App\CommandPattern\WesternRestaurant;
class Program {
public function makeOrder($order) { $result = []; if (in_array('Filet Mignon', $order)) { $result[] = '菲力牛排'; }
if (in_array('Sirloin Steak', $order)) { $result[] = '沙朗牛排'; }
return $result; } }
|
隨著生日蒸蒸日上,
老闆已經沒辦法同時處理客人點餐與煎牛排了(這是兩種職責)。
決定引進我們販賣的機器人廚師,
讓他能專心在記下客人的需求。
需求一:老闆決定到外場服務,透過指令指揮內場的機器人廚師煎牛排
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
namespace App\CommandPattern\WesternRestaurant\Receiver;
abstract class Chef {
public function cookFiletMignon() { return '菲力牛排'; }
public function cookSirloinSteak() { return '沙朗牛排'; } }
|
1 2 3 4 5 6 7 8 9 10
| <?php
namespace App\CommandPattern\WesternRestaurant\Receiver;
use App\CommandPattern\WesternRestaurant\Receiver\Chef;
class RobotChefA extends Chef { }
|
1 2 3 4 5 6 7 8 9 10
| <?php
namespace App\CommandPattern\WesternRestaurant\Receiver;
use App\CommandPattern\WesternRestaurant\Receiver\Chef;
class RobotChefB extends Chef { }
|
1 2 3 4 5 6 7 8
| <?php
namespace App\CommandPattern\WesternRestaurant\Contracts;
interface Command { public function execute(); }
|
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
| <?php
namespace App\CommandPattern\WesternRestaurant;
use App\CommandPattern\WesternRestaurant\Contracts\Command; use App\CommandPattern\WesternRestaurant\Receiver\Chef;
class CookFiletMignonCommand implements Command {
protected $chef;
public function __construct(Chef $chef) { $this->chef = $chef; }
public function execute() { return $this->chef->cookFiletMignon(); } }
|
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
| <?php
namespace App\CommandPattern\WesternRestaurant;
use App\CommandPattern\WesternRestaurant\Contracts\Command; use App\CommandPattern\WesternRestaurant\Receiver\Chef;
class CookSirloinSteakCommand implements Command {
protected $chef;
public function __construct(Chef $chef) { $this->chef = $chef; }
public function execute() { return $this->chef->cookSirloinSteak(); } }
|
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
| <?php
namespace App\CommandPattern\WesternRestaurant;
use App\CommandPattern\WesternRestaurant\Receiver\RobotChefA; use App\CommandPattern\WesternRestaurant\Receiver\RobotChefB;
class Program {
public function makeOrder($order) { $chefA = new RobotChefA(); $chefB = new RobotChefB(); $cookFiletMignonCommand = new cookFiletMignonCommand($chefA); $cookSirloinSteakCommand = new CookSirloinSteakCommand($chefB);
$result = []; if (in_array('Filet Mignon', $order)) { $result[] = $cookFiletMignonCommand->execute(); }
if (in_array('Sirloin Steak', $order)) { $result[] = $cookSirloinSteakCommand->execute(); }
return $result; } }
|
[角色對應關係]
調用者 (Invoker) :老闆
接收者 (Receiver) :機器人廚師
命令 (Command) :煎牛排指令
[單一職責原則]
我們將點餐與煎牛排視作兩種不同的職責。
透過命令來聯繫兩者。
[開放封閉原則]
當新增/修改需求時,不會動到所有程式碼。
(比如:外場老闆不會知道烹調方式的改變、機器人不會知道當前餐廳的優惠)
[依賴反轉原則]
調用者依賴抽象的命令介面。
命令實作抽象的命令介面。
此外命令模式還可以留下點餐紀錄,便於將來結帳、重做餐點呢。
ʕ •ᴥ•ʔ:使用命令模式的老闆,也隱含「人力」資源管理的味道。
(指定誰做什麼餐點)