## 举个例子
> 想吃大闸蟹, 加工的方式有多种,清蒸、姜葱炒、香辣炒、避风塘炒等,可以任意选择,当然不同的方式价格也有所不同。
> 选择一种加工方式后进行下单,厨师做好了会有专门的服务人员送过来,坐着等就可以了……
> 清蒸, 爆炒, 都是你在给厨师下命令, 虽然你不会做菜, 不知道如何清蒸或者爆炒, 但是照样能吃到美味
> 注意这里有一个很重要的角色就是服务员,她帮你下订单,然后把订单传送给厨师,厨师收到订单后根据订单做餐
## 代码示例
```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. 就像军队,将军一声令下,士兵就得分秒无差,准确执行。
![](https://box.kancloud.cn/771ba05886fa8233e7e3ca1b0cf15782_740x337.png)
## 设计要点
**命令模式中主要有四个角色,在设计命令模式时要找到并区分这些角色**
1. **命令(Command)**: 要完成的任务,或要执行的动作,这是命令模式的核心角色。
1. **接收者(Receiver)**: 任务的具体实施方,或行动的真实执行者。
1. **调度者(Invoker)**: 接受任务并发送命令,对接用户的需求并执行内部的命令,负责外部用户与内部命令的交互。
1. **用户(Client)**: 命令的使用者,即真正的用户。
## 优缺点
**策略模式的优点**:
1. 对命令的发送者与接收者进行解耦,使得调用方不用关系具体的行动执行者及如何执行,只要发送正确的命令即可。
1. 可以很方便地增加新的命令。
**策略模式的缺点**:
1. 在一些系统中可能会有很多的命令,而每一个命令都需要一个具体的类去封装,容易使命令的类急剧膨胀。
## 应用场景
1. 希望系统发送一个命令(或信号),任务就能得到处理时,如 GUI 中的各种按钮的单击命令;再如自定义一套消息的响应机制。
1. 需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互时。
1. 需要请一系列的命令组合成一组操作时,可以使用宏命令的方式。