1、定义
将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
2、模式结构
命令模式由四部分组成:
- Command(抽象命令角色):定义命令的接口,声明执行的方法。
- ConcreteCommand(具体命令角色):命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
- Receiver(接受者):真正执行命令的对象。
- Invoker(调用者):要求命令对象执行请求,通常会持有命令对象,也可以持有很多的命令对象。这个是客户端真的触发命令并要求命令执行相应的地方,也就是是相当于使用命令对象的入口。
3、实例
3.1 Command
public interface Command {
public void execute();
// 撤销操作
public void undo();
}
3.2 开灯/关灯/空命令(ConcreteCommand)
public class LightOnCommand implements Command {
private LightReceiver light;
public LightOnCommand(LightReceiver light) {
this.light = light;
}
@Override
public void execute() {
// 调用接收者方法
light.on();
}
@Override
public void undo() {
light.off();
}
}
public class LightOffCommand implements Command {
private LightReceiver light;
public LightOffCommand(LightReceiver light) {
this.light = light;
}
@Override
public void execute() {
// 调用接收者方法
light.off();
}
@Override
public void undo() {
light.on();
}
}
public class NoCommand implements Command {
@Override
public void execute() {
}
@Override
public void undo() {
}
}
3.3 LightReceiver(Receiver)
public class LightReceiver {
public void on() {
System.out.println("电灯打开了。。。");
}
public void off() {
System.out.println("电灯关闭了。。。");
}
}
3.4 遥控器(Invoker)
public class RemoteController {
// 开关按钮的命令数组
private Command[] onCommands;
private Command[] offCommands;
private Command undoCommand;
// 完成按钮的初始化
public RemoteController() {
onCommands = new Command[5];
offCommands = new Command[5];
for(int i = 0; i < 5; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
// 设置你需要的命令
public void setCommand(int no, Command onCommand, Command offCommand) {
onCommands[no] = onCommand;
offCommands[no] = offCommand;
}
// 按开按钮
public void onButtonWasPushed(int no) {
onCommands[no].execute();
// 记住这次操作,用于撤销
undoCommand = onCommands[no];
}
// 按关按钮
public void offButtonWasPushed(int no) {
offCommands[no].execute();
// 记住这次操作,用于撤销
undoCommand = offCommands[no];
}
// 撤销按钮
public void undoButtonWasPushed() {
undoCommand.undo();
}
}
3.5 客户端调用
public class Client {
public static void main(String[] args) {
LightReceiver light = new LightReceiver();
LightOnCommand lightOnCommand = new LightOnCommand(light);
LightOffCommand lightOffCommand = new LightOffCommand(light);
// 调用者
RemoteController remoteController = new RemoteController();
remoteController.setCommand(0, lightOnCommand, lightOffCommand);
System.out.println("------按下开灯按钮------");
remoteController.onButtonWasPushed(0);
System.out.println("------按下关灯按钮------");
remoteController.offButtonWasPushed(0);
System.out.println("------按下撤销按钮------");
remoteController.undoButtonWasPushed();
}
}
4、适用场景
- 需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
- 需要在不同的时间制定请求,将请求排队和执行请求。
- 需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
- 徐亚奥将操作组合在一起,即支持宏命令。
5、在Spring中的应用
分析:
- StatementCallback类似于命令接口(Command)。
- QueryStatementCallback,匿名内部类,实现了命令接口,同时充当命令的接收者。
- JdbcTemplate,命令调用者,其中execute方法中,调用了action.doInStatement方法。
6、优缺点
6.1 优点
- 降低系统的耦合度。
- 新的命令可以很容易地加入到系统中。
- 可以比较容易地设计一个命令队列和宏命令(组合命令)。
- 可以方便地实现对请求的Undo和Redo。
6.2 缺点
- 可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因为某些系统可能需要大量具体命令类,这将影响命令模式的使用。