zoukankan      html  css  js  c++  java
  • 命令模式-实现undo和redo

     这次实验主要是实现多次redo和undo,即程序的撤回和恢复,这里只实现加法的撤回和恢复。

        程序的撤回和恢复就是由所使用的软件来记录操作步骤,可以将数据恢复到某个操作状态。

        撤回这个指令很常见,Windows系统常用的快捷键ctrl+z就可以实现撤回的效果

        恢复目前只在word等文档编辑软件见到。

          

      首先说一下命令模式的结构(参考该类图,使用starUML制作):

        

        Adder类是加法的计算和返回计算后的结果, AbstrCommand是抽象类,定义三个抽象方法,AddCommand类继承AbstrCommand类,对AbstrCommand进行扩展,

      这样就可以灵活的改变命令的内容,和添加新命令。CalculatorForm类是调用AbstrCommand的方法,实现操作,并对操作的结果进行处理。通过该结构可以完成撤回和

      回复的实现。

      该结构又优点,这样设计降低了系统的耦合度,也方便加入新命令。

      接下来说一下算法实现的原理:

        首先要想撤回和恢复的实现,需要有两个栈(链表也可以),一个栈用来存储操作的每个步骤的结果,命名为撤回栈,另一个表用来

      存储撤回栈弹出的数据,命名为恢复栈。在进行加法操作的时候需要在将最新的结果压入撤回栈(保存最新操作),恢复栈清空(每次进行加法操作,

      需要清空撤回栈弹出的数据),在撤回栈的时候需要将撤回栈的栈顶弹出,并将其压入恢复栈(保存),在恢复时需要将恢复栈的栈顶弹出,并将其

      压入撤回栈,这样就完成了基本的实现,不要忘了再加上栈的空的判断。

      栈的使用:stack<Object>  stack = new Stack<Object>();    定义 (说明类型)

           Object j=stack.peek();   返回栈顶元素的值

           Object j=stack.pop();    弹出栈顶元素的值,j是弹出的值

           Object j=stack.push(Object element);    将值压入栈

      源代码:

      //实现加法的计算和返回计算的值

      
    1 public class Adder {
    2     private int num =0;
    3     public int add(int value) {
    4         num+=value;
    5         return num;
    6     }
    7 }
    Adder类

      //抽象命令类

      
    1 public abstract class AbstractCommand {
    2     public abstract int execute(int value);
    3     
    4     public abstract int undo();
    5     
    6     public abstract int redo();
    7 }
    AbstractCommand 类

     //加法命令类

      
     1 import java.util.Stack;
     2 
     3 
     4 
     5 public class AddCommand extends AbstractCommand {
     6     private Adder adder = new Adder();
     7     private Stack<Integer> unStack = new Stack<Integer>();// 返回栈,用来记录所做的每一步操作,用于撤回
     8     private Stack<Integer> reStack = new Stack<Integer>();// 重复栈,用来存储返回栈弹出的数据,由于重复
     9 
    10     /**
    11      * 撤回
    12      */
    13     public int undo() {
    14         int i=0;
    15         if (unStack.isEmpty()) {
    16             
    17             i=-1;
    18         }else{
    19             Integer pop = unStack.pop();
    20             reStack.push(pop);
    21             if(!unStack.isEmpty()){//判断弹出数据后是否为空,如果为空,说明已撤回到最原始状态
    22                 i=unStack.peek();
    23             }
    24         }
    25         return i;
    26     }
    27 
    28     /**
    29      * 恢复
    30      */
    31     public int redo() {
    32         int i=0;
    33         if (reStack.isEmpty()) {
    34             i=-1;
    35         }else{//撤回时只要可以可以撤回,则返回栈一定有数据
    36             Integer pop = reStack.pop();
    37             unStack.push(pop);
    38             i=pop;
    39         }
    40         return i;
    41     }
    42 
    43     /**
    44      * 执行计算,并进行栈的更新
    45      */
    46     public int execute(int value) {
    47         int v = 0;
    48         if (unStack.isEmpty()) {// 说明还没有数据
    49             v = adder.add(value);
    50             unStack.push(v);
    51         } else {// 需要更新两个栈中的内容,并计算结果,其中返回栈应该更新,重复栈应该清空
    52             v = adder.add(value);
    53             unStack.push(v);
    54             if (!reStack.isEmpty()) {
    55                 for (int i = 0; i < reStack.size(); i++) {
    56                     reStack.pop();
    57                 }
    58             }
    59         }
    60         return v;
    61     }
    62 }
    AddCommand类
      
     1 public class CalculatorForm {
     2     private AbstractCommand command;
     3     public void setCommand(AbstractCommand command) {
     4         this.command =command;
     5     }
     6     /**
     7      * 执行运算
     8      * @param value
     9      */
    10     public void compute(int value) {
    11         command.execute(value);
    12     }
    13     /**
    14      * 撤回
    15      */
    16     public void undo() {
    17         int i = command.undo();
    18         if(i==-1){
    19             System.out.println("缓存中已不存在数据");
    20         }else{
    21             System.out.println("执行成功,运算结果是:"+i);
    22         }
    23     }
    24     /**
    25      * 恢复
    26      */
    27     public void redo() {
    28          int i = command.redo();
    29         if(i==-1){
    30             System.out.println("已恢复至最新数据");
    31         }
    32         else{
    33             System.out.println("执行成功,运算结果是:"+i);
    34         }
    35     }
    36 }
    CalculatorForm(引用命令)类

      //测试结果

      
     1 public class client {
     2     public static void main(String[] args) {
     3         CalculatorForm form = new CalculatorForm();
     4         AddCommand command = new AddCommand();
     5         form.setCommand(command);
     6         //计算
     7         System.out.println("------计算过程-----");
     8         form.compute(1);
     9         form.compute(2);
    10         form.compute(3);
    11         form.compute(4);
    12         //多次撤回
    13         System.out.println("------撤回过程-----");
    14         form.undo();
    15         form.undo();
    16         form.undo();
    17         form.undo();
    18         form.undo();
    19         //多次恢复
    20         System.out.println("------恢复过程-----");
    21         form.redo();
    22         form.redo();
    23         form.redo();
    24         form.redo();
    25         form.redo();
    26     }
    27 }
    client 类

      实验总结:

        通过本次试验,对命令模式有了基本了解,命令模式很容易实现undo和redo,在本次试验我使用了stack栈用来实现多次的撤回和恢复,透彻理解使用两个栈,用来对数据

    进行恢复的原理,就可以很快的解决该问题。

  • 相关阅读:
    [原创]推荐三款强大且漂亮的统计图控件
    使用ATL设计组件(VC6.0)
    COM笔记引用计数
    远程调试
    记事本2
    C++中类的多态与虚函数的使用
    Eclipse常用快捷键
    怎么在Release下调试代码
    MSDN 无法显示网页
    COM笔记接口
  • 原文地址:https://www.cnblogs.com/qingtianxt/p/8076479.html
Copyright © 2011-2022 走看看