命令模式-实现undo和redo

时间:2023-03-09 07:55:17
命令模式-实现undo和redo

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

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

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

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

      命令模式-实现undo和redo

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

    命令模式-实现undo和redo

    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);    将值压入栈

  源代码:

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

  
 public class Adder {
private int num =0;
public int add(int value) {
num+=value;
return num;
}
}

Adder类

  //抽象命令类

  
 public abstract class AbstractCommand {
public abstract int execute(int value); public abstract int undo(); public abstract int redo();
}

AbstractCommand 类

 //加法命令类

  
 import java.util.Stack;

 public class AddCommand extends AbstractCommand {
private Adder adder = new Adder();
private Stack<Integer> unStack = new Stack<Integer>();// 返回栈,用来记录所做的每一步操作,用于撤回
private Stack<Integer> reStack = new Stack<Integer>();// 重复栈,用来存储返回栈弹出的数据,由于重复 /**
* 撤回
*/
public int undo() {
int i=0;
if (unStack.isEmpty()) { i=-1;
}else{
Integer pop = unStack.pop();
reStack.push(pop);
if(!unStack.isEmpty()){//判断弹出数据后是否为空,如果为空,说明已撤回到最原始状态
i=unStack.peek();
}
}
return i;
} /**
* 恢复
*/
public int redo() {
int i=0;
if (reStack.isEmpty()) {
i=-1;
}else{//撤回时只要可以可以撤回,则返回栈一定有数据
Integer pop = reStack.pop();
unStack.push(pop);
i=pop;
}
return i;
} /**
* 执行计算,并进行栈的更新
*/
public int execute(int value) {
int v = 0;
if (unStack.isEmpty()) {// 说明还没有数据
v = adder.add(value);
unStack.push(v);
} else {// 需要更新两个栈中的内容,并计算结果,其中返回栈应该更新,重复栈应该清空
v = adder.add(value);
unStack.push(v);
if (!reStack.isEmpty()) {
for (int i = 0; i < reStack.size(); i++) {
reStack.pop();
}
}
}
return v;
}
}

AddCommand类

  
 public class CalculatorForm {
private AbstractCommand command;
public void setCommand(AbstractCommand command) {
this.command =command;
}
/**
* 执行运算
* @param value
*/
public void compute(int value) {
command.execute(value);
}
/**
* 撤回
*/
public void undo() {
int i = command.undo();
if(i==-1){
System.out.println("缓存中已不存在数据");
}else{
System.out.println("执行成功,运算结果是:"+i);
}
}
/**
* 恢复
*/
public void redo() {
int i = command.redo();
if(i==-1){
System.out.println("已恢复至最新数据");
}
else{
System.out.println("执行成功,运算结果是:"+i);
}
}
}

CalculatorForm(引用命令)类

  //测试结果

  
 public class client {
public static void main(String[] args) {
CalculatorForm form = new CalculatorForm();
AddCommand command = new AddCommand();
form.setCommand(command);
//计算
System.out.println("------计算过程-----");
form.compute(1);
form.compute(2);
form.compute(3);
form.compute(4);
//多次撤回
System.out.println("------撤回过程-----");
form.undo();
form.undo();
form.undo();
form.undo();
form.undo();
//多次恢复
System.out.println("------恢复过程-----");
form.redo();
form.redo();
form.redo();
form.redo();
form.redo();
}
}

client 类

  实验总结:

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

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