这次实验主要是实现多次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 }
//抽象命令类
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 }
//加法命令类
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 }
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 }
//测试结果
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 }
实验总结:
通过本次试验,对命令模式有了基本了解,命令模式很容易实现undo和redo,在本次试验我使用了stack栈用来实现多次的撤回和恢复,透彻理解使用两个栈,用来对数据
进行恢复的原理,就可以很快的解决该问题。