1. 程式人生 > >命令模式-實現undo和redo

命令模式-實現undo和redo

else new object out isp idt .com 行處理 ++

 這次實驗主要是實現多次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棧用來實現多次的撤回和恢復,透徹理解使用兩個棧,用來對數據

進行恢復的原理,就可以很快的解決該問題。

命令模式-實現undo和redo