命令模式-實現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 {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 }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