博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式解密(11)- 命令模式 - 扩展篇(撤销命令)
阅读量:7293 次
发布时间:2019-06-30

本文共 7015 字,大约阅读时间需要 23 分钟。

前言:命令模式内容比较多,这里做了拆分

命令模式基础篇 :

命令模式扩展篇 - 宏命令:

命令模式扩展篇 - 撤销命令:

命令模式扩展篇 - 命令队列:

命令模式扩展篇 - 请求日志:

2-1、撤销命令

有两种基本的思路来实现可撤销的操作:

  1、逆向操作实现:比如被撤销的操作是添加功能,那撤消的实现就变成删除功能;同理被撤销的操作是删除功能,那么撤销的实现就变成添加功能;

  2、存储恢复实现,意思就是把操作前的状态记录下来,然后要撤销操作的时候就直接恢复回去就可以了,可使用备忘录模式(Memento Pattern)来实现(稍后会讲到备忘录模式);

这里主要讲解通过逆向操作来实现撤销(undo):

具体操作:在命令模式中,我们可以通过调用一个命令对象的execute()方法来实现对请求的处理,如果需要撤销(undo)请求,可通过在命令类中增加一个逆向操作来实现。

修改Command接口:

/** * 包含撤销命令的接口*/public interface Command {      //执行方法    void execute();    //撤销方法    void undo();}

下面实例说明:

package com.designpattern.Command.extend.Undo;/** * 包含撤销命令的接口 * @author Json*/public interface Command {    //执行方法    void execute();    //撤销方法    void undo();}
package com.designpattern.Command.extend.Undo;/** * 具体命令 -- 创建目录 * @author Json*/public class CreateDirCommand implements Command {    private String dirName;    MakeDir makeDir;    public CreateDirCommand(MakeDir makeDir,String dirName) {        this.makeDir = makeDir;        this.dirName = dirName;    }        @Override    public void execute() {        makeDir.createDir(dirName);    }        @Override    public void undo() {        makeDir.deleteDir(dirName);    }}
package com.designpattern.Command.extend.Undo;import java.io.File;/** * 命令接受者 * 包含两个命令:创建目录、删除目录 * @author Json*/public class MakeDir {    //创建目录    public void createDir(String name){        File dir = new File(name);        if (dir.exists()) {              System.out.println("创建目录 " + name + " 失败,目标目录已经存在");          }else{            //创建目录              if (dir.mkdirs()) {                System.out.println("创建目录 " + name + " 成功");              } else {                  System.out.println("创建目录 " + name + " 失败");              }          }     }    //删除目录    public void deleteDir(String name){        File dir = new File(name);        if(dir.exists()) {              if(dir.delete()){                System.out.println("删除目录 " + name + " 成功");            }else{                System.out.println("删除目录 " + name + " 失败");            }        }else{            System.out.println("删除目录 " + name + " 失败,目标目录不存在");        }    }}
package com.designpattern.Command.extend.Undo;/** * 请求者 * @author Json*/public class RequestMakeDir {    Command createCommand;    public void setCreateCommand(Command command) {        this.createCommand = command;    }        public void executeCreateCommand(){        createCommand.execute();    }        public void undoCreateCommand(){        createCommand.undo();    }}

测试:

package com.designpattern.Command.extend.Undo;/** * 测试 * @author Json*/public class Client {    public static void main(String[] args) {        String dir = "E:\\command2017";                //创建接收者        MakeDir makeDir = new MakeDir();         //创建具体命令并且指定接收者        Command create_command = new CreateDirCommand(makeDir,dir);        //创建请求者        RequestMakeDir request = new RequestMakeDir();        //设置命令        request.setCreateCommand(create_command);        /***********创建目录及撤销**************/        //创建目录        request.executeCreateCommand();        //撤销        request.undoCreateCommand();    }}

结果:

创建目录 E:\command2017 成功删除目录 E:\command2017 成功

上面例子很简单,大家应该明白了吧!!!

深入一下,提个问题:如何支持多次撤销? 下面有讲解,继续往下看↓↓↓

2-2、多次撤销

我们在使用文本编辑器的时候,经常会遇到撤销的操作,这是就按一下组合键(Ctrl + Z),就会回到上次修改,至于代码要如何实现?

首先还是要先实现各个命令的undo行为(执行与execute相反顺序的操作即可),另外我们还需要一个栈来记录已经被执行过的操作,以支持撤销到初始状态;

下面来改造一下实例:

package com.designpattern.Command.extend.MultiUndo;/** * 包含撤销命令的接口 * @author Json*/public interface Command {    //执行方法    void execute(String dirName);    //撤销方法    void undo();}
package com.designpattern.Command.extend.MultiUndo;import java.util.ArrayList;/** * 具体命令 -- 创建目录 * @author Json*/public class CreateDirCommand implements Command {    private ArrayList
dirNameList; //记录 这里用list实现 private MakeDir makeDir; public CreateDirCommand(MakeDir makeDir) { dirNameList = new ArrayList
(); this.makeDir = makeDir; } @Override public void execute(String dirName) { makeDir.createDir(dirName); dirNameList.add(dirName); } @Override public void undo() { if(dirNameList.size()>0){ makeDir.deleteDir(dirNameList.get(dirNameList.size()-1)); dirNameList.remove(dirNameList.size()-1); }else{ System.out.println("没有需要撤销的操作!"); } }}
package com.designpattern.Command.extend.MultiUndo;import java.io.File;/** * 命令接受者 * 包含两个命令:创建目录、删除目录 * @author Json*/public class MakeDir {    //创建目录    public void createDir(String name){        File dir = new File(name);        if (dir.exists()) {              System.out.println("创建目录 " + name + " 失败,目标目录已经存在");          }else{            //创建目录              if (dir.mkdirs()) {                System.out.println("创建目录 " + name + " 成功");              } else {                  System.out.println("创建目录 " + name + " 失败");              }          }     }    //删除目录    public void deleteDir(String name){        File dir = new File(name);        if(dir.exists()) {              if(dir.delete()){                System.out.println("删除目录 " + name + " 成功");            }else{                System.out.println("删除目录 " + name + " 失败");            }        }else{            System.out.println("删除目录 " + name + " 失败,目标目录不存在");        }    }}
package com.designpattern.Command.extend.MultiUndo;/** * 请求者 * @author Json*/public class RequestMakeDir {    Command createCommand;    public void setCreateCommand(Command command) {        this.createCommand = command;    }        public void executeCreateCommand(String dirName){        createCommand.execute(dirName);    }        public void undoCreateCommand(){        createCommand.undo();    }}

测试:

package com.designpattern.Command.extend.MultiUndo;/** * 测试 * @author Json*/public class Client {    public static void main(String[] args) {        //创建接收者        MakeDir makeDir = new MakeDir();         //创建具体命令并且指定接收者        Command create_command = new CreateDirCommand(makeDir);        //创建请求者        RequestMakeDir request = new RequestMakeDir();        //设置命令        request.setCreateCommand(create_command);        /***********创建目录及撤销**************/        //创建目录        request.executeCreateCommand("E:\\command\\2017");        request.executeCreateCommand("E:\\command\\2018");        request.executeCreateCommand("E:\\command\\2019");        request.executeCreateCommand("E:\\command\\2020");        //多次撤销        request.undoCreateCommand();        request.undoCreateCommand();        request.undoCreateCommand();        request.undoCreateCommand();        request.undoCreateCommand();    }}

结果:

创建目录 E:\command\2017 成功创建目录 E:\command\2018 成功创建目录 E:\command\2019 成功创建目录 E:\command\2020 成功删除目录 E:\command\2020 成功删除目录 E:\command\2019 成功删除目录 E:\command\2018 成功删除目录 E:\command\2017 成功没有需要撤销的操作!

上面的例子存在瑕疵:不知道大家有没有看出来:

我们没有保存命令对象的历史状态(执行情况,比如成功、失败),可以通过引入一个命令集合或其他方式来存储每一次操作时命令的状态,这样实现多次撤销操作就完美了(这里就不在列举实例了,请自行撸代码吧)。

PS:除了undo操作外,还可以采用同undo类似的方式实现恢复(redo)操作,即恢复所撤销的操作(或称为二次撤销)。

 

PS:源码地址    

  

PS:源码地址 

 

转载于:https://www.cnblogs.com/JsonShare/p/7206513.html

你可能感兴趣的文章
顺序表的静态存储
查看>>
linux下 文件夹和文件的字符集编码方式转换
查看>>
软件测试氛围受到什么因素影响
查看>>
大数据实战之环境搭建(七)
查看>>
ISCSI
查看>>
技术关键词_0120625
查看>>
手工配置LVS
查看>>
sudo用法
查看>>
如何创建配置链接邮箱
查看>>
觉得还不错的国内外编程技术网站、论坛列表
查看>>
SCDPM2012R2(二)SCDPM2012R2的安装
查看>>
Rsync命令参数详解
查看>>
mysql日志简单备份小脚本
查看>>
java.net.SocketException: Permission denied
查看>>
Esxi 5.0虚拟机网络不通问题解决
查看>>
替换禁用语(指定关键字)的过滤器(StopWordsFilter)
查看>>
数学经典教材
查看>>
菜鸟的IT道路ing (五)
查看>>
httpfox抓取ip数据包
查看>>
使用Redux和ngrx构建更好的Angular2应用(一)
查看>>