備忘錄模式提供了一種物件狀態的撤銷實作機制,當系統中某一物件需要恢復到某一歷史狀態時可以使用備忘錄模式來進行設計
模式動機
人人都有后悔的時候,在軟體使用程序中難免會出現一些誤操作,如不小心洗掉了某些文字或圖片,資料填入錯誤等,對于這些誤操作,需要提供一種后悔藥機制,讓系統可以回到誤操作前的狀態,這就是備忘錄模式的模式動機
模式定義
在不破壞封裝的前提下,捕獲一個物件的內部狀態,并在該物件之外保存這個狀態,這樣可以在以后將物件恢復到原先保存的狀態,備忘錄模式是一種物件行為型模式,其別名為 Token
模式結構

-
Originator(原發器)
原發器可以創建一個備忘錄,并存盤它的當前內部狀態,也可以使用備忘錄來恢復其內部狀態,一般將需要保存內部狀態的類設計為原發器,
-
Memento(備忘錄)
存盤原發器的內部狀態,根據原發器來決定保存哪些內部狀態,需要注意的是,除了原發器本身與負責人之外,備忘錄物件不能直接供其他類使用,
-
Caretaker(負責人)
負責人又稱管理者,它負責保存備忘錄,但是不能對備忘錄的內容進行操作或檢查,
模式分析
前面已經說了,備忘錄模式就是用來吃后悔藥的,理解起來并不難,關鍵在于如何設計備忘錄類和負責人類,
備忘錄中存盤的是原發器的中間狀態,因此需要防止原發器以外的其他物件訪問備忘錄,也不能在備忘錄物件之外保存原發器狀態,如果暴露其內部狀態將違反封裝的原則,
為了實作對備忘錄物件的封裝,需要對備忘錄的呼叫進行控制,對于原發器而言,它可以呼叫備忘錄的所有資訊,允許原發器訪問先前狀態的所有資料,對于負責人而言,只負責備忘錄的保存并將備忘錄傳遞給其他物件,對于其他物件而言,只需要從負責人處取出備忘錄物件并將原發器物件的狀態恢復,而無須關心備忘錄的保存狀態,
下面通過一個實體來進一步理解備忘錄模式,
模式實體
某系統提供了用戶資訊操作模塊,用戶可以修改自己的各項資訊,用戶在進行了錯誤操作后可以恢復到操作之前的狀態,

-
原發器 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("------------------------"); } } -
運行結果

模式優缺點
備忘錄模式優點:
- 提供了一種狀態恢復的實作機制,使得用戶可以方便地回到特定的一個歷史步驟
- 實作了資訊的封裝,備忘錄只保存原發器的狀態,不會被其他代碼修改,采用堆疊來存盤備忘錄物件可以實作多次撤銷操作,可以通過在負責人中定義集合物件來存盤多個備忘錄,
備忘錄模式缺點:
- 每保存一次物件的狀態都需要消耗記憶體資源,資源消耗過大
模式適用環境
在以下情況可以使用備忘錄模式:
- 保存一個物件在某一時刻的狀態或部分狀態
- 如果用一個介面來讓其他物件得到這些狀態,將會暴露物件的實作細節并破壞封裝性,一個物件不希望外界直接訪問得到其內部狀態,通過負責人可以間接訪問其內部狀態
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/8597.html
標籤:設計模式
