命令模式
定义
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
角色
- Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令。
- ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现。
- Client类:最终的客户端调用类。
- Invoker类:调用者,负责调用命令。
- Receiver类:接收者,负责接收命令并且执行命令。
示例
调用者,持有命令对象
public class MyInvoker {
private Command command;
public Command getCommand() {
return command;
}
public void setCommand(Command command) {
this.command = command;
}
public void invoke(){
command.action();
}
}
命令接口,一个命令对应一个事件
public interface Command {
public void action();
}
命令实现A,持有接收者对象
public class CommandImplA implements Command{
private MyReceiver receiver;
public CommandImplA(MyReceiver receiver) {
this.receiver = receiver;
}
@Override
public void action() {
this.receiver.executeA();
}
}
命令实现B
public class CommandImplB implements Command {
private MyReceiver receiver;
public CommandImplB(MyReceiver receiver) {
this.receiver = receiver;
}
@Override
public void action() {
this.receiver.executeB();
}
}
命令实现C
public class CommandImplC implements Command {
private MyReceiver receiver;
public CommandImplC(MyReceiver receiver) {
this.receiver = receiver;
}
@Override
public void action() {
this.receiver.executeC();
}
}
接受者,主要负责执行事件
public class MyReceiver {
public void executeA(){
System.out.println("执行A事件");
}
public void executeB(){
System.out.println("执行B事件");
}
public void executeC(){
System.out.println("执行C事件");
}
}
测试类
public class CommandTest {
public static void main(String[] args) {
MyInvoker myInvoker = new MyInvoker();
MyReceiver myReceiver = new MyReceiver();
myInvoker.setCommand(new CommandImplA(myReceiver));
myInvoker.invoke();
myInvoker.setCommand(new CommandImplB(myReceiver));
myInvoker.invoke();
myInvoker.setCommand(new CommandImplC(myReceiver));
myInvoker.invoke();
}
}
分析
- Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”。
- 实现Command接口的具体命令对象ConcreteCommand有时候根据需要可能会保存一些额外的状态信息。
- 通过使用Compmosite模式,可以将多个命令封装为一个“复合命令”MacroCommand。
- Command模式与C#中的Delegate有些类似。但两者定义行为接口的规范有所区别:Command以面向对象中的“接口-实现”来定义行为接口规范,更严格,更符合抽象原则;Delegate以函数签名来定义行为接口规范,更灵活,但抽象能力比较弱。
- 使用命令模式会导致某些系统有过多的具体命令类。某些系统可能需要几十个,几百个甚至几千个具体命令类,这会使命令模式在这样的系统里变得不实际。