1.概述
命令模式是一个高内聚的模式,其定义为:将一个请求封装成一个对象,从而让你使用不同的请求吧客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
命令模式通用类图如下:
Receiver 接收者,就是干活的角色,命令传递到这里应该被执行的。
Command 命令角色,需要执行的命令都在这里声明。
Invoker 调用者角色,接收到命令并执行命令。
2.优缺点
2.1 优点
类间解耦 调用者和接收者之间没有任何依赖关系,调用者只需调用Command抽象类的execute方法,不需要了解是那个接收者。
可拓展性 Command的子类可以非常容易的扩展。
结合其他模式更优秀 结合责任链模式实现命令族解析任务;结合模板方法模式可以减少Command子类的膨胀问题。
2.2 缺点
命令越多,Command的子类就越多,使用时需要慎重考虑。
3.实践案例
通用类图中client还需了解到都有哪些具体执行者才能发布命令(指定谁去执行那个命令),也可以只指定去执行那个命令,具体要谁执行,可以在命令类里面规定。进一步减少类间的耦合,下面案例按照后者写代码。
创建调用者类,@setter即是set方法
/**
* @author chiangtaol
* @date 2020-12-03
* @describe 命令调用者
*/
@Setter
public class Invoker {
// 需要知道要执行什么命令
private CommandAbstract command;
/**
* 执行高层命令,调用具体的命令
*/
public void action(){
command.execute();
}
}
创建命令抽象类和具体命令类
/**
* @author chiangtaol
* @date 2020-12-03
* @describe 命令抽象类
*/
public abstract class CommandAbstract {
protected final ReceiverAbstract receiverAbstract;
// 实现类必须都定义一个接受者(如果命令复杂可以改为集合类型)
public CommandAbstract(ReceiverAbstract receiver){
this.receiverAbstract = receiver;
}
// 每个命令类都必须有一个执行命令的方法
public abstract void execute();
}
/**
* @author chiangtaol
* @date 2020-12-03
* @describe 具体的命令1
*/
public class Command1 extends CommandAbstract{
public Command1(){
super(new Receiver1());
}
@Override
public void execute() {
// 这个命令的业务逻辑
super.receiverAbstract.doSomething();
}
}
/**
* @author chiangtaol
* @date 2020-12-03
* @describe 命令2
*/
public class Command2 extends CommandAbstract{
public Command2(){
super(new Receiver2());
}
@Override
public void execute() {
super.receiverAbstract.doSomething();
}
}
创建接收者抽象类和具体接收者,也就是实际执行命令的角色
/**
* @author chiangtaol
* @date 2020-12-03
* @describe 接收者抽象类
*/
public abstract class ReceiverAbstract {
// 接受者必须做点什么
public abstract void doSomething();
}
/**
* @author chiangtaol
* @date 2020-12-03
* @describe 命令接收者, 具体的执行者
*/
public class Receiver1 extends ReceiverAbstract{
@Override
public void doSomething() {
System.out.println("执行者1做点什么...");
}
}
/**
* @author chiangtaol
* @date 2020-12-03
* @describe 命令接受者
*/
public class Receiver2 extends ReceiverAbstract{
@Override
public void doSomething() {
System.out.println("执行者2做点什么...");
}
}
在测试类中向调用者发布命令
/**
* @author chiangtaol
* @date 2020-12-03
* @describe
*/
class InvokerTest {
@Test
void action() {
Invoker invoker = new Invoker();
// 高层模块指定调用者执行一个命令1
invoker.setCommand(new Command1());
invoker.action();
// 高层模块指定调用者执行一个命令2
invoker.setCommand(new Command2());
invoker.action();
}
}
运行结果如下:
执行者1做点什么... 执行者2做点什么...
高层模块不需要知道谁具体执行,只要告诉调用者执行那个命令即可。