1. 程式人生 > 實用技巧 >php 設計模式之 命令模式

php 設計模式之 命令模式



1. 命令模式

命令模式,也稱為動作或者事務模式

如用餐廳舉列,選單是這個實際的命令,服務員是這個命令的傳送者,而廚師是這個命令的接收者。

那麼,這個模式解決了什麼呢?當你要修改選單的時候,只需要和服務員說就好了,她會轉達給廚師,也就是說,我們實現了顧客和廚師的解耦。也就是 呼叫者與實現者的解耦

但是命令模式能夠做到的是 讓一個命令接收者實現多個命令(服務員下單、拿酒水、上菜),或者 把一條命令轉達給多個實現者(熱菜廚師、冷盤廚師、主食師傅)。


2. 實列

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;
    }
}

// 命令傳送者(服務員)
$invoker = new Invoker();

// 命令接收者(廚師)
$receiverA = new Receiver('A');

// 具體執行的命令內容(選單)
$commandOne = new ConcreteCommand($receiverA, 'A');

// 執行命令
$invoker->setCommand($commandOne);
$invoker->exec();
$invoker->undo();

// 新加一個單獨的執行者,只執行一個命令
$invokerA = new Invoker();
$invokerA->setCommand($commandOne);
$invokerA->exec();

// 命令A已經執行了,再次執行全部的命令執行者,A命令的state判斷無法生效
$invoker->exec();