[设计模式] 命令模式
作者:互联网
[设计模式] 命令模式
目录
手机用户请
横屏
获取最佳阅读体验,REFERENCES
中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。
平台 | 地址 |
---|---|
CSDN | https://blog.csdn.net/sinat_28690417 |
简书 | https://www.jianshu.com/u/3032cc862300 |
个人博客 | https://yiyuery.github.io/NoteBooks/ |
命令模式 将请求封装成对象,这可以让你使用不同的请求、队列或者是日志请求来参数化其他对象。命令模式一般支持定义撤销操作。
命令模式实现
简单命令
首先来让我们实现一个能开灯的遥控命令场景。
//简单命令接口定义,内部含有一个执行方法
public interface Command {
/**
* 执行
*/
void execute();
}
定义一个开灯的命令接口实现:
public class LightOnCommand implements Command {
/**
* 执行
*/
@Override
public void execute() {
System.out.println("The light has been turned on!");
}
}
定义一个遥控器:
@Data
public class SimpleRemoteController {
/**
* 命令
*/
private Command command;
/**
* 遥控按钮被按下时,执行命令
*/
public void buttonWasPressed(){
command.execute();
}
}
Ex.1
/**
* 测试遥控器按下开灯的按钮
*/
@Test
public void testX1(){
SimpleRemoteController remoteController = new SimpleRemoteController();
remoteController.setCommand(new LightOnCommand());
//按键
remoteController.buttonWasPressed();
//The light has been turned on!
}
批量命令
如果是需要一组命令的执行呢?
补充定义
一个命令NoCommand
,用于默认命令的信息打印。
public class NoCommand implements Command {
/**
* 执行
*/
@Override
public void execute() {
System.out.println("Command has not been defined!");
}
}
public class MultipleRemoteController {
Command[] commands;
public MultipleRemoteController(int num) {
commands = new Command[num];
for (Command command : commands) {
command = new NoCommand();
}
}
public void setCommand(int index,Command command){
commands[index] = command;
}
/**
* 遥控按钮被按下时,执行命令
*/
public void buttonWasPressed(int index){
commands[index].execute();
}
}
Ex.2
/**
* 测试遥控器按下开灯的按钮
*/
@Test
public void testX2(){
MultipleRemoteController remoteController = new MultipleRemoteController(2);
remoteController.setCommand(0,new LightOnCommand());
remoteController.setCommand(1,new TVOnCommand());
//按键
remoteController.buttonWasPressed(0);
remoteController.buttonWasPressed(1);
//The light has been turned on!
//TV has been turned on!
}
简单撤销
定义两组命令,每次在执行开启操作前将对应的关闭操作写入缓存变量,在执行撤销方法时,执行即可。
//为了实现代码复用(可以暂时不关注,只关注于宏命令的使用即可),将遥控器的公共部分抽离到一个抽象基类中:
public abstract class AbstractRemoteController<T,K extends Command> {
protected K undoCommand;
/**开启操作命令数组*/
protected K[] onCommands;
/**关闭操作命令数组*/
protected K[] offCommands;
public boolean supportUndo(){
return true;
}
/**
* 设置命令
* @param index
* @param onCommand
* @param offCommand
*/
public abstract void setCommand(int index, T onCommand, T offCommand);
/**
* 遥控按钮被按下时,执行命令
*/
public abstract void buttonWasPressed(int index);
/**
* 开启操作的撤销按钮
*/
public void undoButtonWasPressed(){
//该基类的定义使用了模版模式,是否支持undo操作由子类决定
if(supportUndo()){
undoCommand.execute();
}
}
}
//支持简单撤销的遥控器
public class SupportUndoRemoteController extends AbstractRemoteController<Command,Command> {
public SupportUndoRemoteController(int num) {
onCommands = new Command[num];
offCommands = new Command[num];
for (int i = 0; i < num; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
@Override
public void setCommand(int index,Command onCommand,Command offCommand){
onCommands[index] = onCommand;
offCommands[index] = offCommand;
}
/**
* 遥控按钮被按下时,执行命令
*/
@Override
public void buttonWasPressed(int index){
onCommands[index].execute();
undoCommand = offCommands[index];
}
}
Ex.3
/**
* 支持开启操作的简单撤销
*/
@Test
public void testX3(){
SupportUndoRemoteController supportUndoRemoteController = new SupportUndoRemoteController(2);
//设置灯的开和关命令
supportUndoRemoteController.setCommand(0,new LightOnCommand(),new LightOffCommand());
//设置电视的开和关命令
supportUndoRemoteController.setCommand(1,new TVOnCommand(),new TVOffCommand());
//先开电视后开灯
supportUndoRemoteController.buttonWasPressed(1);
supportUndoRemoteController.buttonWasPressed(0);
//开电视后撤销再开灯
supportUndoRemoteController.buttonWasPressed(1);
supportUndoRemoteController.undoButtonWasPressed();
supportUndoRemoteController.buttonWasPressed(0);
//TV has been turned on!
//The light has been turned on!
//TV has been turned on!
//TV has been turned off!
//The light has been turned on!
}
宏命令
定义一组命令的执行,类似于 MicroSoft 常用的宏定义函数一样
假定我们定义一个宏命令实现回家后的一个智能操作:包含开灯和开电视,并要求它支持撤销能力。
//宏命令
public class MacroCommand implements Command {
Command[] commands;
public MacroCommand(Command[] commands) {
this.commands = commands;
}
/**
* 执行
*/
@Override
public void execute() {
for (Command command : commands) {
command.execute();
}
}
}
//支持宏命令的遥控器
public class SupportMacroRemoteController extends AbstractRemoteController<MacroCommand,Command> {
public SupportMacroRemoteController(int num) {
onCommands= new Command[num];
offCommands = new Command[num];
for (int i = 0; i <num ; i++) {
onCommands[i]= new NoCommand();
offCommands[i]= new NoCommand();
}
}
@Override
public void setCommand(int index, MacroCommand onMacroCommand, MacroCommand offMacroCommand){
onCommands[index] = onMacroCommand;
offCommands[index] = offMacroCommand;
}
/**
* 遥控按钮被按下时,执行命令
*
* @param index
*/
@Override
public void buttonWasPressed(int index) {
onCommands[index].execute();
undoCommand = offCommands[index];
}
@Override
public boolean supportUndo() {
return true;
}
}
//开电视
public class TVOnCommand implements Command {
/**
* 执行
*/
@Override
public void execute() {
System.out.println("TV has been turned on!");
}
}
Ex.4
/**
* 宏命令测试
*/
@Test
public void testX4(){
SupportMacroRemoteController supportUndoRemoteController = new SupportMacroRemoteController(2);
Command[] partyOn = new Command[]{new LightOnCommand(),new TVOnCommand()};
Command[] partyOff = new Command[]{new LightOffCommand(),new TVOffCommand()};
supportUndoRemoteController.setCommand(0,new MacroCommand(partyOn),new MacroCommand(partyOff));
//开Party后撤销
supportUndoRemoteController.buttonWasPressed(0);
supportUndoRemoteController.undoButtonWasPressed();
//The light has been turned on!
//TV has been turned on!
//The light has been turned off!
//TV has been turned off!
}
标准撤销方式
针对于命令场景的撤销操作,其实我们可以直接定义一个undo
操作接口在Command
中,此处考虑到演示的代码结构,我们在补充一个接口继承Command
来实现
public interface SupportUndoCommand extends Command {
/**
* 撤销操作
*/
void undo();
}
对应的undo方式执行也调整下实现:
//新的开灯方法
public class LightOnCommand2 implements SupportUndoCommand {
/**
* 执行
*/
@Override
public void execute() {
System.out.println("The light has been turned on!");
}
/**
* 撤销操作
*/
@Override
public void undo() {
System.out.println("The light turn on has been canceled!");
}
}
//新的开电视方法
public class TVOnCommand2 implements SupportUndoCommand {
/**
* 执行
*/
@Override
public void execute() {
System.out.println("TV has been turned on!");
}
/**
* 撤销操作
*/
@Override
public void undo() {
System.out.println("TV turn on has been canceled!");
}
}
//支持undo的遥控器
public class NewSupportUndoRemoteController extends AbstractRemoteController<SupportUndoCommand,SupportUndoCommand> {
public NewSupportUndoRemoteController(int num) {
onCommands = new SupportUndoCommand[num];
for (int i = 0; i < num; i++) {
onCommands[i] = new NoUndoCommand();
}
}
@Override
public void setCommand(int index, SupportUndoCommand onCommand, SupportUndoCommand offCommand){
onCommands[index] = onCommand;
}
/**
* 遥控按钮被按下时,执行命令
*/
@Override
public void buttonWasPressed(int index){
onCommands[index].execute();
}
/**
* 开启操作的撤销按钮
*/
@Override
public void undoButtonWasPressed(){
for (SupportUndoCommand onCommand : onCommands) {
onCommand.undo();
}
}
}
Ex.5
/**
* 宏命令 & 标准撤销测试
*/
@Test
public void testX5(){
NewSupportUndoRemoteController newSupportUndoRemoteController = new NewSupportUndoRemoteController(1);
SupportUndoCommand[] partyOn2 = new SupportUndoCommand[]{new LightOnCommand2(),new TVOnCommand2()};
SupportUndoCommand[] partyOff2 = new SupportUndoCommand[]{new LightOffCommand2(),new TVOffCommand2()};
newSupportUndoRemoteController.setCommand(0,new MacroCommand2(partyOn2),new MacroCommand2(partyOff2));
//开Party后撤销
newSupportUndoRemoteController.buttonWasPressed(0);
newSupportUndoRemoteController.undoButtonWasPressed();
//The light has been turned on!
//TV has been turned on!
//The light turn on has been canceled!
//TV turn on has been canceled!
}
总结
模式特点
- 将发出请求的对象和执行的对象解耦
- 被解耦的两者之间是通过命令对象之间进行沟通的,命令对象封装了接受者和一个/组动作
- 调用者通过调用命令对象的
execute
发出请求,后者根据这个进行响应 - 调用者可以接受命令当做传入的参数,甚至在运行时动态地进行
- 命令还支持撤销操作的定义,做法是实现一个
undo
方法来回到execute
被执行前的状态 - 宏命令是命令的一种简单延伸,允许调用多个命令
敲黑板 !!!!
- 命令模式致力于发送请求和执行请求的对象解耦操作!
更多
扫码关注
架构探险之道
,回复文章标题,获取本文相关源码和资源链接
知识星球(扫码加入获取历史源码和文章资源链接)
标签:void,turned,模式,命令,Command,been,new,设计模式,public 来源: https://blog.51cto.com/u_15263565/2886091