## 舉個例子
> 想吃大閘蟹, 加工的方式有多種,清蒸、姜蔥炒、香辣炒、避風塘炒等,可以任意選擇,當然不同的方式價格也有所不同。
> 選擇一種加工方式后進行下單,廚師做好了會有專門的服務人員送過來,坐著等就可以了……
> 清蒸, 爆炒, 都是你在給廚師下命令, 雖然你不會做菜, 不知道如何清蒸或者爆炒, 但是照樣能吃到美味
> 注意這里有一個很重要的角色就是服務員,她幫你下訂單,然后把訂單傳送給廚師,廚師收到訂單后根據訂單做餐
## 代碼示例
```php
<?php
// 廚師
class Chef {
public function steamFood($originalMaterial) {
echo $originalMaterial . "清蒸中..." . PHP_EOL;
return "清蒸" . $originalMaterial;
}
public function stirFriedFood($originalMaterial) {
echo $originalMaterial . "爆炒中..." . PHP_EOL;
return "香辣炒" . $originalMaterial;
}
}
// 訂單
abstract class Order {
protected $chef;
protected $name;
protected $originalMaterial;
public function __construct($name, $originalMaterial) {
$this->chef = new Chef();
$this->name = $name;
$this->originalMaterial = $originalMaterial;
}
public function getDisplayName() {
return $this->name . $this->originalMaterial;
}
public function processingOrder() {
}
}
// 清蒸
class SteamedOrder extends Order {
public function __construct($originalMaterial) {
parent::__construct("清蒸", $originalMaterial);
}
public function processingOrder() {
if ($this->chef) {
return $this->chef->steamFood($this->originalMaterial);
}
return "";
}
}
// 香辣炒
class SpicyOrder extends Order {
public function __construct($originalMaterial) {
parent::__construct("香辣炒", $originalMaterial);
}
public function processingOrder() {
if ($this->chef) {
return $this->chef->stirFriedFood($this->originalMaterial);
}
return "";
}
}
// 服務員
class Waiter {
protected $name;
protected $order;
public function __construct($name) {
$this->name = $name;
$this->order = null;
}
public function receiveOrder($order) {
$this->order = $order;
echo "服務員" . $this->name . ":您的 " . $order->getDisplayName() . " 訂單已經收到,請耐心等待" . PHP_EOL;
}
public function placeOrder() {
$food = $this->order->processingOrder();
echo "服務員" . $this->name . ":您的餐 " . $food . " 已經準備好,請您慢用!" . PHP_EOL;
}
}
// 測試代碼
$waiter = new Waiter("Anna");
$steamedOrder = new SteamedOrder("大閘蟹");
echo "客戶David:我要一份" . $steamedOrder->getDisplayName();
echo PHP_EOL;
$waiter->receiveOrder($steamedOrder);
$waiter->placeOrder();
echo PHP_EOL;
$spicyOrder = new SpicyOrder("大閘蟹");
echo "客戶Tony:我要一份" . $steamedOrder->getDisplayName();
$waiter->receiveOrder($spicyOrder);
$waiter->placeOrder();
```
```
D:\soft\php72\php.exe D:\project\php_dp\index.php
客戶David:我要一份清蒸大閘蟹
服務員Anna:您的 清蒸大閘蟹 訂單已經收到,請耐心等待
大閘蟹清蒸中...
服務員Anna:您的餐 清蒸大閘蟹 已經準備好,請您慢用!
客戶Tony:我要一份清蒸大閘蟹服務員Anna:您的 香辣炒大閘蟹 訂單已經收到,請耐心等待
大閘蟹爆炒中...
服務員Anna:您的餐 香辣炒大閘蟹 已經準備好,請您慢用!
Process finished with exit code 0
```
## 什么是命令模式?
> 將一個請求封裝成一個對象,從而讓你使用不同的請求把客戶端參數化
1. 命令模式的最大特點是將具體的命令與對應的接收者相關聯(捆綁),使得調用方不用關心具體的行動執行者及如何執行
2. 只要發送正確的命令,就能準確無誤地完成相應的任務。
3. 就像軍隊,將軍一聲令下,士兵就得分秒無差,準確執行。

## 設計要點
**命令模式中主要有四個角色,在設計命令模式時要找到并區分這些角色**
1. **命令(Command)**: 要完成的任務,或要執行的動作,這是命令模式的核心角色。
1. **接收者(Receiver)**: 任務的具體實施方,或行動的真實執行者。
1. **調度者(Invoker)**: 接受任務并發送命令,對接用戶的需求并執行內部的命令,負責外部用戶與內部命令的交互。
1. **用戶(Client)**: 命令的使用者,即真正的用戶。
## 優缺點
**策略模式的優點**:
1. 對命令的發送者與接收者進行解耦,使得調用方不用關系具體的行動執行者及如何執行,只要發送正確的命令即可。
1. 可以很方便地增加新的命令。
**策略模式的缺點**:
1. 在一些系統中可能會有很多的命令,而每一個命令都需要一個具體的類去封裝,容易使命令的類急劇膨脹。
## 應用場景
1. 希望系統發送一個命令(或信號),任務就能得到處理時,如 GUI 中的各種按鈕的單擊命令;再如自定義一套消息的響應機制。
1. 需要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互時。
1. 需要請一系列的命令組合成一組操作時,可以使用宏命令的方式。