定义

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤销操作。

使用场景

  1. 认为是命令的地方都可以使用命令模式,日落 GUI中的每个按钮都是一条命令,模拟cmd

    1. 用户点餐,电视遥控器
    2. 系统需要支持命令的撤销和恢复操作也可考虑用命令模式
  2. 在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
  3. 敏捷开发原则告诉我们,不要为代码添加基于猜测、实际不需要的功能。
    如果不清楚一个系统是否需要命令模式,不要着急去实现。实现命令模式不难,只有当需要命令模式时,重构才有意义

代码实现

//抽象命令类
abstract class Command
{
    protected Receiver receiver;

    public Command(Receiver receiver)
    {
        this.receiver = receiver;
    }
    
    public abstract void ExecuteCommand();

}

//具体命令类
class ConcreteCommand: Command
{
    public ConcreteCommand(Receiver receiver): base(receiver) { }

    public override void ExecuteCommand()
    {
        receiver.Action();
    }

}

//执行者
//执行 和 撤销(结合备忘录模式 还原状态)
//Command 可使用列表,日志功能
class Invoker
{
    private Command command;

    public void SetCommand(Command command)
    {
        this.command = command;
    }
    
    public void ExcuteCommand()
    {
        command.ExcuteCommand();
    }

}

//命令接收者
class Receiver
{
     public void Action()
     {
          //执行命令
     }
}


void Main()
{
     Receiver receiver = new Receiver(); //命令接收者
     Command Com1 = new ConcreteCommand(receiver); //具体命令
     Invoker invoker = new Invoker(); //命令发起者
     invoker.SetCommand(com1); //下令
     invoker.ExcuteCommand(); //执行命令
}

// 执行者 -> 具体命令 -> 接收者

优点&缺点

  1. 较容易设计一个命令队列
  2. 在需要的情况下,可以较容易地将命令记录日志
  3. 允许接收请求的一方决定是否要否决请求
  4. 可以容易实现对请求的撤销和重做
  5. 加入新的请求不会影响其他的类,因此增加新的具体命令类和容易
  6. 最关键的优点 命令模式把一个操作的对象 与 知道怎么执行一个操作的对象分隔开
  7. 使用命令模式可能会导致某些系统有过多的具体命令类。