備忘錄模式提供了一種對象狀態的撤銷實現機制,當系統中某一對象須要恢復到某一歷史狀態時可使用備忘錄模式來進行設計java
人人都有後悔的時候,在軟件使用過程當中不免會出現一些誤操做,如不當心刪除了某些文字或圖片,數據填入錯誤等,對於這些誤操做,須要提供一種後悔藥機制,讓系統能夠回到誤操做前的狀態,這就是備忘錄模式的模式動機函數
在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣能夠在之後將對象恢復到原先保存的狀態。備忘錄模式是一種對象行爲型模式,其別名爲 Token測試
Originator(原發器)this
原發器能夠建立一個備忘錄,並存儲它的當前內部狀態,也可使用備忘錄來恢復其內部狀態。通常將須要保存內部狀態的類設計爲原發器。設計
Memento(備忘錄)rest
存儲原發器的內部狀態,根據原發器來決定保存哪些內部狀態。須要注意的是,除了原發器自己與負責人以外,備忘錄對象不能直接供其餘類使用。code
Caretaker(負責人)對象
負責人又稱管理者,它負責保存備忘錄,可是不能對備忘錄的內容進行操做或檢查。blog
前面已經說了,備忘錄模式就是用來吃後悔藥的,理解起來並不難,關鍵在於如何設計備忘錄類和負責人類。接口
備忘錄中存儲的是原發器的中間狀態,所以須要防止原發器之外的其餘對象訪問備忘錄。也不能在備忘錄對象以外保存原發器狀態,若是暴露其內部狀態將違反封裝的原則。
爲了實現對備忘錄對象的封裝,須要對備忘錄的調用進行控制。對於原發器而言,它能夠調用備忘錄的全部信息,容許原發器訪問先前狀態的全部數據。對於負責人而言,只負責備忘錄的保存並將備忘錄傳遞給其餘對象。對於其餘對象而言,只須要從負責人處取出備忘錄對象並將原發器對象的狀態恢復,而無須關心備忘錄的保存狀態。
下面經過一個實例來進一步理解備忘錄模式。
某系統提供了用戶信息操做模塊,用戶能夠修改本身的各項信息,用戶在進行了錯誤操做後能夠恢復到操做以前的狀態。
原發器 UserInfoDTO(用戶信息類)
package dp.memento; public class UserInfoDTO { private String account; private String password; public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // 建立一個備忘錄對象 public Memento saveMemento() { return new Memento(account, password); } // 根據備忘錄對象恢復原發器狀態 public void restoreMemento(Memento memento) { this.account = memento.getAccount(); this.password = memento.getPassword(); } public void show() { System.out.println("Account: " + this.account); System.out.println("Password: " + this.getPassword()); } }
備忘錄 Memento
設計備忘錄時須要考慮到封裝性,即除了原發器類,不容許其餘類來調用其構造函數與相關方法。通常將備忘錄類和原發器類定義在同一包中來實現封裝,使用默認訪問標識符來定義備忘錄類,即保證包內可見性。
package dp.memento; class Memento { private String account; private String password; public Memento(String account, String password) { this.account = account; this.password = password; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
負責人 Caretaker
package dp.memento; public class Caretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }
客戶端測試類 Client
import dp.memento.UserInfoDTO; import dp.memento.Caretaker; public class Client { public static void main(String[] args) { UserInfoDTO user = new UserInfoDTO(); // 建立負責人 Caretaker caretaker = new Caretaker(); user.setAccount("zhangsan"); user.setPassword("123456"); System.out.println("狀態一"); user.show(); // 保存備忘錄 caretaker.setMemento(user.saveMemento()); System.out.println("------------------------"); user.setPassword("11111111"); System.out.println("狀態二"); user.show(); System.out.println("------------------------"); // 從備忘錄中恢復 user.restoreMemento(caretaker.getMemento()); System.out.println("回到狀態一"); user.show(); System.out.println("------------------------"); } }
運行結果
備忘錄模式優勢:
備忘錄模式缺點:
在如下狀況可使用備忘錄模式: