一、備忘錄模式的定義與特點
備忘錄(Memento)模式的定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,以便以后當需要時能將該對象恢復到原先保存的狀態。該模式又叫快照模式。
備忘錄模式能記錄一個對象的內部狀態,當用戶后悔時能撤銷當前操作,使數據恢復到它原先的狀態。
二、備忘錄模式優缺點
備忘錄模式是一種對象行為型模式,其主要優點如下:
- 提供了一種可以恢復狀態的機制。當用戶需要時能夠比較方便地將數據恢復到某個歷史的狀態。
- 實現了內部狀態的封裝。除了創建它的發起人之外,其他對象都不能夠訪問這些狀態信息。
- 簡化了發起人類。發起人不需要管理和保存其內部狀態的各個備份,所有狀態信息都保存在備忘錄中,並由管理者進行管理,這符合單一職責原則。
其主要缺點是:
- 資源消耗大。如果要保存的內部狀態信息過多或者特別頻繁,將會占用比較大的內存資源。
三、備忘錄模式的實現
備忘錄模式的核心是設計備忘錄類以及用於管理備忘錄的管理者類,備忘錄模式的主要角色如下:
- 發起人(Originator)角色:記錄當前時刻的內部狀態信息,提供創建備忘錄和恢復備忘錄數據的功能,實現其他業務功能,它可以訪問備忘錄里的所有信息。
- 備忘錄(Memento)角色:負責存儲發起人的內部狀態,在需要的時候提供這些內部狀態給發起人。
- 管理者(Caretaker)角色:對備忘錄進行管理,提供保存與獲取備忘錄的功能,但其不能對備忘錄的內容進行訪問與修改。
備忘錄模式的結構圖如圖所示:

實現代碼如下:
public class MementoPattern { public static void main(String[] args) { Originator or=new Originator(); Caretaker cr=new Caretaker(); or.setState("S0"); System.out.println("初始狀態:"+or.getState()); cr.setMemento(or.createMemento()); //保存狀態 or.setState("S1"); System.out.println("新的狀態:"+or.getState()); or.restoreMemento(cr.getMemento()); //恢復狀態 System.out.println("恢復狀態:"+or.getState()); } } //備忘錄 class Memento { private String state; public Memento(String state) { this.state=state; } public void setState(String state) { this.state=state; } public String getState() { return state; } } //發起人 class Originator { private String state; public void setState(String state) { this.state=state; } public String getState() { return state; } public Memento createMemento() { return new Memento(state); } public void restoreMemento(Memento m) { this.setState(m.getState()); } } //管理者 class Caretaker { private Memento memento; public void setMemento(Memento m) { memento=m; } public Memento getMemento() { return memento; } }
測試結果如下:
初始狀態:S0
新的狀態:S1
恢復狀態:S0
四、備忘錄模式的應用場景
前面學習了備忘錄模式的定義與特點、結構與實現,現在來看該模式的以下應用場景。
- 需要保存與恢復數據的場景,如玩游戲時的中間結果的存檔功能。
- 需要提供一個可回滾操作的場景,如 Word、記事本、Photoshop,Eclipse 等軟件在編輯時按 Ctrl+Z 組合鍵,還有數據庫中事務操作。
五、備忘錄模式的擴展
在前面介紹的備忘錄模式中,有單狀態備份的例子,也有多狀態備份的例子。下面介紹備忘錄模式如何同原型模式混合使用。在備忘錄模式中,通過定義“備忘錄”來備份“發起人”的信息,而原型模式的 clone() 方法具有自備份功能,所以,如果讓發起人實現 Cloneable 接口就有備份自己的功能,這時可以刪除備忘錄類,其結構圖如圖所示:

代碼如下所示:
public class PrototypeMemento { public static void main(String[] args) { OriginatorPrototype or=new OriginatorPrototype(); PrototypeCaretaker cr=new PrototypeCaretaker(); or.setState("S0"); System.out.println("初始狀態:"+or.getState()); cr.setMemento(or.createMemento()); //保存狀態 or.setState("S1"); System.out.println("新的狀態:"+or.getState()); or.restoreMemento(cr.getMemento()); //恢復狀態 System.out.println("恢復狀態:"+or.getState()); } } //發起人原型 class OriginatorPrototype implements Cloneable { private String state; public void setState(String state) { this.state=state; } public String getState() { return state; } public OriginatorPrototype createMemento() { return this.clone(); } public void restoreMemento(OriginatorPrototype opt) { this.setState(opt.getState()); } public OriginatorPrototype clone() { try { return (OriginatorPrototype) super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); } return null; } } //原型管理者 class PrototypeCaretaker { private OriginatorPrototype opt; public void setMemento(OriginatorPrototype opt) { this.opt=opt; } public OriginatorPrototype getMemento() { return opt; } }
運行結果如下:
初始狀態:S0
新的狀態:S1
恢復狀態:S0
