1. 概念
    • 将一个请求封装(命令的封装)为一个对象,从而使用你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
    • 命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分隔开,委派给不同的对象。
    • 请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
  1. 角色
    • 命令(command)角色:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。
    • 具体命令(ConcreteCommand)角色:定义一个接收者和行为之间的弱耦合;实现Execute()方法,负责调用接收到的相应操作。Execute()方法通常叫做执行方法。
    • 客户(client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者。
    • 请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。
    • 接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。
  2. 优点和缺点
    • 优点:
      • 命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分离开。
      • 命令类与其他任何别的类一样,可以修改和推广。
      • 可以把命令对象聚合在一起,合成为合成命令。
      • 可以很容易的加入新的命令类。
    • 缺点:
      • 可能会导致某些系统有过多的具体命令类。
  3. 应用场景
    • 抽象出待执行的动作以参数化对象。Command模式是回调机制的一个面向对象的替代品。
    • 在不同的时刻指定、排列和执行请求。
    • 支持取消操作
    • 支持修改日志
    • 用构建在原语操作上的高层操作构建一个系统。Command模式提供了对事务进行建模的方法。Command有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。
<?php
//抽象命令接口
interface Command
{
    //命令执行
    public function execute();
}

//宏命令(命令的组合)
//宏命令接口
interface MacroCommand extends Command
{
    //宏命令聚集管理方法,可以删除一个命令
    public function remove(Command $command);

    //宏命令聚集管理方法,可以添加一个命令
    public function add(Command $command);
}

//命令的实现
//复制命令
class CopyCommand implements Command
{
    private $receiver;
    public function __construct(Receiver $receiver)
    {
        $this->receiver = $receiver;
    }

    public function execute()
    {
        $this->receiver->copy();
    }
}

//粘贴命令
class PasteCommand implements Command
{
    private $receiver;
    public function __construct(Receiver $receiver)
    {
        $this->receiver = $receiver;
    }

    public function execute()
    {
        $this->receiver->paste();
    }
}

//命令接收者执行命令
class Receiver
{
    private $name;
    public function __construct($name)
    {
        $this->name = $name;
    }

    public function copy()
    {
        echo $this->name . '执行copy命令';
    }

    public function paste()
    {
        echo $this->name . '执行paste命令';
    }
}

//命令请求者,用于发送请求
class Invoker
{
    private $command;
    public function __construct(Command $command)
    {
        $this->command = $command;
    }

    public function action()
    {
        $this->command->execute();
    }
}

//实现宏命令
class TestMacroCommand implements MacroCommand
{
    private $commands;

    public function __construct()
    {
        $this->commands = [];
    }
    //宏命令聚集管理方法,可以删除一个命令
    public function remove(Command $command)
    {
        $index = array_search($command, $this->commands);
        if ($index === false) {
            return false;
        } else {
            unset($this->commands[$index]);
            return true;
        }
    }

    //宏命令聚集管理方法,可以添加一个命令
    public function add(Command $command)
    {
        return array_push($this->commands, $command);
    }

    public function execute()
    {
        if (!is_array($this->commands)) {
            return false;
        } else {
            foreach ($this->commands as $command) {
                //通知改变
                $command->execute();
            }
        }

        return true;
    }
}

//客户端
$receiver = new Receiver('gd');
$copy_command = new CopyCommand($receiver);
$paste_command = new PasteCommand($receiver);

//添加命令到宏命令
$macro_command = new TestMacroCommand();
$macro_command->add($copy_command);
$macro_command->add($paste_command);

$invoker = new Invoker($macro_command);
$invoker->action();