描述
定义
将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。其别名为动作(Action)模式或事务(Transaction)模式。
类型
对象行为型模式
动机
经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,使用命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。
UML类图
实现
主要角色
- Command:抽象命令类
- 声明执行操作execute的抽象接口。
- Receiver:接收者
- 负责具体实施和执行一个请求。
- 任何类都可能作为一个接收者。
- ConcreteCommand:具体命令类
- 将接收者对象和操作进行绑定。
- 实现execute方法,负责调用接收者的相应操作。
- Invoker:请求者
- 负责调用命令对象执行请求。
- Client:客户类
- 创建一个具体命令ConcreteCommand对象并确定其接收者。
示例
-
Command:抽象命令类
interface Command { void execute(); }
-
Receiver:接收者
public class Receiver { public void action() { System.out.println("执行操作"); } }
-
ConcreteCommand:具体命令类,调用Receiver的一些操作以执行请求。
public class ConcreteCommand implements Command { //持有相应的接收者对象 private Receiver receiver = null; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { //通常会转调接收者对象的相应方法,让接收者来真正执行功能 receiver.action(); } }
-
Invoker:请求者,通过调用Command对象的Execute操作来提交一个请求。
public class Invoker { private Command command = null; public Invoker(Command command) { this.command = command; } public void action() { command.execute(); } }
-
Client:客户类,Client创建一个ConcreteCommand对象并指定它的Receiver对象。
public class Client { public static void main(String[] args) { Receiver receiver = new Receiver(); Command command = new ConcreteCommand(receiver); Invoker invoker = new Invoker(command); //执行方法 invoker.action(); } }
适用场景
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。Command模式是回调机制的面向对象的替代品。
- 如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
优点
- 解耦调用者和接收者,调用者实现功能时只需要调用Command抽象类的execute方法就可以,不需要知道到底是哪个接收者执行。
- 更好的扩展性,增加新的Command子类而无需改变已有的类。
- 能够很容易地组合成复合命令。
- 更灵活的控制,可以动态地对请求进行参数化、队列化和日志化等操作。
缺点
- 类膨胀,针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类。
相关模式
- Composite模式可被用来实现复合命令。
- Memento模式可用来保持某个状态,可用保存的状态来取消或重做这个命令的效果。