1. 意图(Intent)

将命令封装成对象中,具有以下作用:

  • 使用命令来参数化其它对象
  • 将命令放入队列中进行排队
  • 将命令的操作记录到日志中
  • 支持可撤销的操作

命令模式优点

  • 类间解耦:调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用 Command 抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。
  • 可扩展性:Command的子类可以非常容易地扩展,而调用者 Invoker 和高层次的模块Client不产生严 重的代码耦合。
  • 命令模式结合其他模式会更优秀:

    1. - 命令模式可以结合责任链模式,实现命令族解析任务;
    2. - 结合模板方法模式,则可以减少 Command子类的膨胀问题。

    命令模式缺点

    命令模式也是有缺点的,请看Command的子类:如果有N个命令,问题就出来了,Command的子类就可不是几个,而是N个,这个类膨胀得非常大,这个就需要读者在项目中慎重考虑使用。

    2. 类图(Class Diagram)

    c44a0342-f405-4f17-b750-e27cf4aadde2.png

  • Command:命令

  • Receiver: 命令接收者,也就是命令真正的执行者
  • Invoker: 通过它来调用命令
  • Client: 可以设置命令与命令的接收者

3. 实现(Implementation)

I 基础结构

命令接口 [ Command ]

public interface Command{
    void Execute();
}

具体命令实现类 [ ConcreteCommand ]

public class ConcreteCommand extends Command{

    protected Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        super(receiver);
    }

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

接收者类:命令真正的执行者 [ Receiver ]

public class Receiver{

    public void Action(){
        Console.WriteLine("执行请求!");
    }
}

调用者类:通过 Invoker 来调用执行

public class Invoker{
       // 接收者和调用者是单向关联关系,调用者的类成员变量引用了接收者
    private Command command;

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

    public void ExecuteCommand(){
        command.Execute();
    }
}

客户端演示:

public class Client {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(r);
        Invoker invoker = new Invoker();

        invoker.SetCommand(command);
        invoker.ExecuteCommand();
    }
}
//输出:执行请求!

命令模式的意图是将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
命令模式主要解决的问题是在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不合适。

在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合,这是命令模式的使用场景。
系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式
命令模式的实现过程通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。

II 遥控器案例

设计一个遥控器,可以控制电灯开关。
e6bded8e-41a0-489a-88a6-638e88ab7666.jpg
命令接口 [ Command ]

public interface Command {
    void execute();
}

[ ConcreteCommand ]

开灯命令实现类

public class LightOnCommand implements Command {
    // 接收者和调用者是单向关联关系,调用者成员变量引用了接收者
    Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        // 接受者真正执行命令
        light.on();
    }
}

关灯命令实现类

public class LightOffCommand implements Command {

    Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.off();
    }
}

接收者灯类:命令真正的执行者 [ Receiver ]

public class Light {

    public void on() {
        System.out.println("Light is on!");
    }

    public void off() {
        System.out.println("Light is off!");
    }
}

调用者遥控器类:[ Invoker ]

public class Invoker {
    // 命令和调用者是聚合关系,命令是调用者类的成员变量
    private Command[] onCommands;
    private Command[] offCommands;
    private final int slotNum = 7;

    public Invoker() {
        this.onCommands = new Command[slotNum];
        this.offCommands = new Command[slotNum];
    }

    public void setOnCommand(Command command, int slot) {
        onCommands[slot] = command;
    }

    public void setOffCommand(Command command, int slot) {
        offCommands[slot] = command;
    }

    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
    }

    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
    }
}

客户端演示:

public class Client {
    public static void main(String[] args) {
        Invoker invoker = new Invoker();
        Light light = new Light();
        Command lightOnCommand = new LightOnCommand(light);
        Command lightOffCommand = new LightOffCommand(light);
        invoker.setOnCommand(lightOnCommand, 0);
        invoker.setOffCommand(lightOffCommand, 0);
        invoker.onButtonWasPushed(0);
        invoker.offButtonWasPushed(0);
    }
}


4. JDK