在先前的文章《一文了解PHP中的原型模式》中我們介紹了PHP中的原型模式,以下這篇文章帶大家了解一下PHP中的指令模式。
指令模式,也稱為動作或交易模式,許多教材會用餐廳來舉例。作為顧客的我們是命令的下達者,服務員是這個命令的接收者,菜單是這個實際的命令,而廚師是這個命令的執行者。
那麼,這個模式解決了什麼呢?當你要修改菜單的時候,只需要和服務生說就好了,她會轉達給廚師,也就是說,我們實現了顧客和廚師的解耦。也就是呼叫者與實現者的解耦。
當然,很多設計模式可以做到這一點,但是命令模式能夠做到的是讓一個命令接收者實現多個命令(服務員下單、拿酒水、上菜),或者把一條命令轉達給多位實現者(熱菜廚師、涼菜廚師、主食師傅)。這才是命令模式真正發揮的地方! !
GoF定義:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支援可撤銷的操作
#GoF類別圖
##程式碼實作
class Invoker { public $command; public function __construct($command) { $this->command = $command; } public function exec() { $this->command->execute(); } }
abstract class Command { protected $receiver; public function __construct(Receiver $receiver) { $this->receiver = $receiver; } abstract public function execute(); } class ConcreteCommand extends Command { public function execute() { $this->receiver->action(); } }
class Receiver { public $name; public function __construct($name) { $this->name = $name; } public function action() { echo $this->name . '命令执行了!', PHP_EOL; } }
// 准备执行者 $receiverA = new Receiver('A'); // 准备命令 $command = new ConcreteCommand($receiverA); // 请求者 $invoker = new Invoker($command); $invoker->exec();
完整程式碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/09.command/source/ command.php<?php class Invoker { private $command = []; public function setCommand(Command $command) { $this->command[] = $command; } public function exec() { if(count($this->command) > 0){ foreach ($this->command as $command) { $command->execute(); } } } public function undo() { if(count($this->command) > 0){ foreach ($this->command as $command) { $command->undo(); } } } } abstract class Command { protected $receiver; protected $state; protected $name; public function __construct(Receiver $receiver, $name) { $this->receiver = $receiver; $this->name = $name; } abstract public function execute(); } class ConcreteCommand extends Command { public function execute() { if (!$this->state || $this->state == 2) { $this->receiver->action(); $this->state = 1; } else { echo $this->name . '命令正在执行,无法再次执行了!', PHP_EOL; } } public function undo() { if ($this->state == 1) { $this->receiver->undo(); $this->state = 2; } else { echo $this->name . '命令未执行,无法撤销了!', PHP_EOL; } } } class Receiver { public $name; public function __construct($name) { $this->name = $name; } public function action() { echo $this->name . '命令执行了!', PHP_EOL; } public function undo() { echo $this->name . '命令撤销了!', PHP_EOL; } } // 准备执行者 $receiverA = new Receiver('A'); $receiverB = new Receiver('B'); $receiverC = new Receiver('C'); // 准备命令 $commandOne = new ConcreteCommand($receiverA, 'A'); $commandTwo = new ConcreteCommand($receiverA, 'B'); $commandThree = new ConcreteCommand($receiverA, 'C'); // 请求者 $invoker = new Invoker(); $invoker->setCommand($commandOne); $invoker->setCommand($commandTwo); $invoker->setCommand($commandThree); $invoker->exec(); $invoker->undo(); // 新加一个单独的执行者,只执行一个命令 $invokerA = new Invoker(); $invokerA->setCommand($commandOne); $invokerA->exec(); // 命令A已经执行了,再次执行全部的命令执行者,A命令的state判断无法生效 $invoker->exec();登入後複製
我們的手機工廠和餐廳其實並沒有什麼兩樣,當我們需要代工廠來製作手機時,也是先下訂單,這個訂單就可以看做是命令。在這個訂單中,我們會規定好需要用到的配件,什麼型號的CPU,什麼型號的內存,預裝什麼系統之類的。然後代工廠的工人們就會根據這個訂單來進行生產。在這個過程中,我不用關心是某一個工人還是一群工人來執行這個訂單,我只需要將這個訂單交給和我們對接的人就可以了,然後只管等著手機生產出來進行驗收咯! !
https://github.com/zhangyue0503/designpatterns-php/blob/master/09.command/source/command-up.php
簡訊發送類別圖
#https://github.com/zhangyue0503/designpatterns-php/blob/ master/09.command/source/command-message.php<?php class SendMsg { private $command = []; public function setCommand(Command $command) { $this->command[] = $command; } public function send($msg) { foreach ($this->command as $command) { $command->execute($msg); } } } abstract class Command { protected $receiver = []; public function setReceiver($receiver) { $this->receiver[] = $receiver; } abstract public function execute($msg); } class SendAliYun extends Command { public function execute($msg) { foreach ($this->receiver as $receiver) { $receiver->action($msg); } } } class SendJiGuang extends Command { public function execute($msg) { foreach ($this->receiver as $receiver) { $receiver->action($msg); } } } class SendAliYunMsg { public function action($msg) { echo '【阿X云短信】发送:' . $msg, PHP_EOL; } } class SendAliYunPush { public function action($msg) { echo '【阿X云推送】发送:' . $msg, PHP_EOL; } } class SendJiGuangMsg { public function action($msg) { echo '【极X短信】发送:' . $msg, PHP_EOL; } } class SendJiGuangPush { public function action($msg) { echo '【极X推送】发送:' . $msg, PHP_EOL; } } $aliMsg = new SendAliYunMsg(); $aliPush = new SendAliYunPush(); $jgMsg = new SendJiGuangMsg(); $jgPush = new SendJiGuangPush(); $sendAliYun = new SendAliYun(); $sendAliYun->setReceiver($aliMsg); $sendAliYun->setReceiver($aliPush); $sendJiGuang = new SendJiGuang(); $sendAliYun->setReceiver($jgMsg); $sendAliYun->setReceiver($jgPush); $sendMsg = new SendMsg(); $sendMsg->setCommand($sendAliYun); $sendMsg->setCommand($sendJiGuang); $sendMsg->send('这次要搞个大活动,快来注册吧!!');登入後複製##
- 在這個例子中,仍然是多命令多執行者的模式
- 可以將這個例子與抽象工廠進行對比,同樣的功能使用不同的設計模式來實現,但是要注意的是,抽象工廠更多的是為了生產對象返回對象,而命令模式則是一種行為的選擇
- 我們可以看出命令模式非常適合形成命令隊列,多命令讓命令可以一條一條執行下去
- 它允許接收的一方決定是否要否決請求,Receiver做為實現者擁有更多的話語權
原文地址:https://juejin .cn/post/6844903950768930823
作者:硬核心專案經理
推薦學習:《PHP影片教學》
以上是深入淺析PHP中的指令模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!