前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[设计模式] 命令模式

[设计模式] 命令模式

作者头像
架构探险之道
发布2019-08-26 17:41:06
3910
发布2019-08-26 17:41:06
举报
文章被收录于专栏:架构探险之道架构探险之道

[设计模式] 命令模式

手机用户请 横屏获取最佳阅读体验, REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。

平台

地址

CSDN

https://blog.csdn.net/sinat_28690417

简书

https://www.jianshu.com/u/3032cc862300

个人博客

https://yiyuery.github.io/NoteBooks/

命令模式 将请求封装成对象,这可以让你使用不同的请求、队列或者是日志请求来参数化其他对象。命令模式一般支持定义撤销操作。

命令模式实现

简单命令

首先来让我们实现一个能开灯的遥控命令场景。

代码语言:javascript
复制
//简单命令接口定义,内部含有一个执行方法
public interface Command {

    /**
     * 执行
     */
    void execute();
}

定义一个开灯的命令接口实现:

代码语言:javascript
复制
public class LightOnCommand implements Command {
    /**
     * 执行
     */
    @Override
    public void execute() {
        System.out.println("The light has been turned on!");
    }
}

定义一个遥控器:

代码语言:javascript
复制
@Data
public class SimpleRemoteController {

    /**
     * 命令
     */
    private Command command;

    /**
     * 遥控按钮被按下时,执行命令
     */
    public void buttonWasPressed(){
        command.execute();
    }
}

Ex.1

代码语言:javascript
复制
/**
 * 测试遥控器按下开灯的按钮
 */
@Test
public void testX1(){
    SimpleRemoteController remoteController = new SimpleRemoteController();
    remoteController.setCommand(new LightOnCommand());
    //按键
    remoteController.buttonWasPressed();

    //The light has been turned on!
}

批量命令

如果是需要一组命令的执行呢?

补充定义一个命令 NoCommand,用于默认命令的信息打印。

代码语言:javascript
复制
public class NoCommand implements Command {
    /**
     * 执行
     */
    @Override
    public void execute() {
        System.out.println("Command has not been defined!");
    }
}
代码语言:javascript
复制
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

代码语言:javascript
复制
/**
 * 测试遥控器按下开灯的按钮
 */
@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!
}

简单撤销

定义两组命令,每次在执行开启操作前将对应的关闭操作写入缓存变量,在执行撤销方法时,执行即可。

代码语言:javascript
复制
//为了实现代码复用(可以暂时不关注,只关注于宏命令的使用即可),将遥控器的公共部分抽离到一个抽象基类中:
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

代码语言:javascript
复制
/**
 * 支持开启操作的简单撤销
 */
@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 常用的宏定义函数一样

假定我们定义一个宏命令实现回家后的一个智能操作:包含开灯和开电视,并要求它支持撤销能力。

代码语言:javascript
复制
//宏命令
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;
    }
}
代码语言:javascript
复制
//开电视
public class TVOnCommand implements Command {
    /**
     * 执行
     */
    @Override
    public void execute() {
        System.out.println("TV has been turned on!");
    }
}

Ex.4

代码语言:javascript
复制
/**
 * 宏命令测试
 */
@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来实现

代码语言:javascript
复制
public interface SupportUndoCommand extends Command {

    /**
     * 撤销操作
     */
    void undo();
}

对应的undo方式执行也调整下实现:

代码语言:javascript
复制
//新的开灯方法
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

代码语言:javascript
复制
/**
    * 宏命令 & 标准撤销测试
    */
@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被执行前的状态
  • 宏命令是命令的一种简单延伸,允许调用多个命令

敲黑板 !!!!

  • 命令模式致力于发送请求和执行请求的对象解耦操作!
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构探险之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • [设计模式] 命令模式
    • 命令模式实现
      • 简单命令
      • 批量命令
      • 简单撤销
      • 宏命令
      • 标准撤销方式
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档