命令模式

对象行为型模式

模式动机

软件设计中,经常需要向某些对象发送请求,但并不知道接收者是谁,也不知道请求的哪个操作,我们只需要在程序运行时指定具体的请求接收者即可。

此时命令模式可以使请求发送者和接收者之间消除耦合。

发送者和接收者之间没有直接引用关系,耦合放在了命令与发送者和命令与接收者之间,发送命令的对象只需要知道如何发送请求,不必知道如何完成(消除和发送者、和命令具体实现的耦合)

应用

出于上述考量,命令模式将一个请求封装成一个对象,可以用不同请求对客户端进行参数化,可以使请求排队、记录请求日志等,并且支持撤销操作,

命令模式包含如下角色:

  • 抽象命令类Command
  • 具体命令类ConcreteCommand
  • 调用者Invoker
  • 接收者Receiver
  • 客户端类Client

分析

  • 命令模式本质是封装命令,分割发出命令的责任和执行命令的责任
  • 每个命令都是一个请求操作、一个对象,请求方发出请求要求执行操作,接收方收到请求并执行,中间的桥接者就是请求(命令),而请求方和发送方彼此解耦,双方都不需要知道对方的接口,也不需要对方的引用
  • 命令模式引入抽象命令接口,发送方面向抽象命令接口编程,只有实现了抽象命令接口的具体命令才能和接收者关联

典型代码如下:

public abstract class Command {
public abstract void execute();
}
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command=command;
}
public void setCommand(Command command) {
this.command=command;
}
//业务方法,用于调用命令类的方法
public void call() {
command.execute();
}
}
public class ConcreteCommand extends Command {
private Receiver receiver;
public void execute() {
receiver.action();
}
}
public class Receiver {
public void action() {
//具体操作
}
}

命令模式顺序图:

实例:电视机遥控器

电视机是请求的接收者,遥控器是请求的发送者,遥控器上有一些按钮对于不同操作。有三个具体命令类实现抽象命令接口,代表三个操作:打开、关闭、换台。

优点

  1. 降低系统耦合度
  2. 新命令方便添加
  3. 比较容易设计一个命令队列或者组合命令
  4. 方便实现redo和undo

缺点

可能会导致系统具有过多的具体命令类,因为每一个具体命令都需要设计一个具体命令类,某些系统可能需要大量具体命令类。

适用场合

  1. 系统要解耦请求发送者和接收者,使得两者不直接交互
  2. 需要在不同时间指定请求、将请求排队和执行请求
  3. 需要支持撤销和恢复操作
  4. 需要组合一组操作(宏命令)

Java使用命令模式实现了AWT/Swing GUI的委派事件模型(Delegation Event Model, DEM)

命令模式扩展

实现撤销操作

实现宏命令

宏命令即组合命令,本身组合了多个命令,这些命令也可能是宏命令,在调用宏命令的execute方法时,递归调用每个成员命令的execute方法,成员同理(如果也是宏命令),如此递归下去直到递归出口。

(•‿•)