1. 程式人生 > >請求傳送者與接收者解耦——命令模式(四)

請求傳送者與接收者解耦——命令模式(四)

5 撤銷操作的實現

       在命令模式中,我們可以通過呼叫一個命令物件的execute()方法來實現對請求的處理,如果需要撤銷(Undo)請求,可通過在命令類中增加一個逆向操作來實現。

微笑

擴充套件

除了通過一個逆向操作來實現撤銷(Undo)外,還可以通過儲存物件的歷史狀態來實現撤銷,後者可使用備忘錄模式(Memento Pattern)來實現

       下面通過一個簡單的例項來學習如何使用命令模式實現撤銷操作:

       Sunny軟體公司欲開發一個簡易計算器,該計算器可以實現簡單的數學運算,還可以對運算實施撤銷操作。

       Sunny

軟體公司開發人員使用命令模式設計瞭如圖5所示結構圖,其中計算器介面類CalculatorForm充當請求傳送者,實現了資料求和功能的加法類Adder充當請求接收者,介面類可間接呼叫加法類中的add()方法實現加法運算,並且提供了可撤銷加法運算的undo()方法。

5  簡易計算器結構圖

本例項完整程式碼如下所示:

  1. //加法類:請求接收者
  2. class Adder {  
  3.     privateint num=0//定義初始值為0
  4.     //加法操作,每次將傳入的值與num作加法運算,再將結果返回
  5.     publicint add(int value) {  
  6.         num += value;  
  7.         return num;  
  8.     }  
  9. }  
  10. //抽象命令類
  11. abstractclass AbstractCommand {  
  12.     publicabstractint execute(int value); //宣告命令執行方法execute()
  13.     publicabstractint undo(); //宣告撤銷方法undo()
  14. }  
  15. //具體命令類
  16. class ConcreteCommand extends AbstractCommand {  
  17.     private Adder adder = new Adder();  
  18.     privateint value;  
  19.     //實現抽象命令類中宣告的execute()方法,呼叫加法類的加法操作
  20. publicint execute(int value) {  
  21.         this.value=value;  
  22.         return adder.add(value);  
  23.     }  
  24.     //實現抽象命令類中宣告的undo()方法,通過加一個相反數來實現加法的逆向操作
  25.     publicint undo() {  
  26.         return adder.add(-value);  
  27.     }  
  28. }  
  29. //計算器介面類:請求傳送者
  30. class CalculatorForm {  
  31.     private AbstractCommand command;  
  32.     publicvoid setCommand(AbstractCommand command) {  
  33.         this.command = command;  
  34.     }  
  35.     //呼叫命令物件的execute()方法執行運算
  36.     publicvoid compute(int value) {  
  37.         int i = command.execute(value);  
  38.         System.out.println("執行運算,運算結果為:" + i);  
  39.     }  
  40.     //呼叫命令物件的undo()方法執行撤銷
  41.     publicvoid undo() {  
  42.         int i = command.undo();  
  43.         System.out.println("執行撤銷,運算結果為:" + i);  
  44.     }  
  45. }  

       編寫如下客戶端測試程式碼:

  1. class Client {  
  2.     publicstaticvoid main(String args[]) {  
  3.         CalculatorForm form = new CalculatorForm();  
  4.         AbstractCommand command;  
  5.         command = new ConcreteCommand();  
  6.         form.setCommand(command); //向傳送者注入命令物件
  7.         form.compute(10);  
  8.         form.compute(5);  
  9.         form.compute(10);  
  10.         form.undo();  
  11.     }  
  12. }  


編譯並執行程式,輸出結果如下:

執行運算,運算結果為:10

執行運算,運算結果為:15

執行運算,運算結果為:25

執行撤銷,運算結果為:15

疑問

思考

如果連續呼叫“form.undo()”兩次,預測客戶端程式碼的輸出結果。

       需要注意的是在本例項中只能實現一步撤銷操作,因為沒有儲存命令物件的歷史狀態,可以通過引入一個命令集合或其他方式來儲存每一次操作時命令的狀態,從而實現多次撤銷操作。除了Undo操作外,還可以採用類似的方式實現恢復(Redo)操作,即恢復所撤銷的操作(或稱為二次撤銷)。

微笑

練習

修改簡易計算器原始碼,使之能夠實現多次撤銷(Undo)和恢復(Redo)