命令模式简介
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
类图:
核心类说明:
Client : 即请求发出者,通过调用Invoker方法发出请求。
Invoker : 请求的调用者,内部持有具体请求的引用。
ConcreteCommand :封装的请求对象,内部持有Receiver对象。
Receiver:请求接受者,根据请求对象的指挥进行不同的反应。
命令模式将 Client → Receiver 的基本逻辑拆解为4个部分,使请求的发出者无需关心最终接受者的执行逻辑,并且由于Invoker作为中间对象存在,使得对执行命令本身进行额外操作可以很方便的实现(如日志记录、命令回退),命令对象的封装使命令便于修改和扩展,并且可以很方便的进行命令组合产生新的命令。
使用示例
public class Receiver {
public void doSometing1(){
System.out.println("doSth1");
}
public void doSometing2(){
System.out.println("doSth2");
}
public void doSometing3(){
System.out.println("doSth3");
}
}
public abstract class Command {
private Receiver receiver;
public void setReceiver(Receiver receiver) {
this.receiver = receiver;
}
public Receiver getReceiver() {
return receiver;
}
public abstract void execute();
}
public class ConcreteCommand01 extends Command {
public ConcreteCommand01() {
super();
super.setReceiver(new Receiver());
}
@Override
public void execute() {
super.getReceiver().doSometing1();
super.getReceiver().doSometing2();
}
}
public class ConcreteCommand02 extends Command {
public ConcreteCommand02() {
super();
super.setReceiver(new Receiver());
}
@Override
public void execute() {
super.getReceiver().doSometing2();
super.getReceiver().doSometing3();
}
}
public class Invoker {
private Command command;
public void invokeCommand(Command command){
command.execute();
}
}
public class Client {
public static void main(String[] args) {
Command command01 = new ConcreteCommand01();
Command command02 = new ConcreteCommand02();
Invoker invoker = new Invoker();
invoker.invokeCommand(command01);
System.out.println("================");
invoker.invokeCommand(command02);
}
}
运行结果:
doSth1
doSth2
================
doSth2
doSth3
总结
优缺点
优点:
- Invoker的存在使命令执行之前有了更多的设计空间(日志记录、命令回滚、拒绝执行命令、命令队列等)
- 对命令进行封装,使命令易于扩展和修改
- 命令发出者和接受者解耦,使发出者不需要知道命令的具体执行过程即可执行
缺点:
- 命令过多会导致需要编写大量的命令对象
使用场景
命令执行过程较为复杂且可能存在变化,需要对执行命令动作本身进行额外操作,此时可以考虑使用命令模式