备忘录模式(MEMENTO),又称Token,通过在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以待需要时将该对象恢复到原先保存的状态,属于对象行为型模式。备忘录模式很适合实现软件中的撤销和重做功能,在字处理软件,图像编辑软件,数据库管理软件中十分常见。游戏里也常常可以使用备忘录模式来保存游戏的状态,如游戏失败前的状态,游戏暂停时的状态,以备玩家重新接着死亡前的关卡继续或从暂停状态恢复,这样使游戏更人性化。
一、使用场景
1、保存一个对象在某个时刻的全部或部分状态,以待需要时重新恢复到该状态。
2、防止通过接口来让其他对象直接操作对象的内部状态,避免暴露对象的实现细节并破坏对象的封装性。
二、UML图

三、Java实现
- package study.patterns.memento;
-
-
-
-
-
-
-
-
-
-
-
- public class MementoPattern {
-
- public static void main(String[] args) {
- Caretaker taker = new Caretaker();
- Originator or = new Originator();
- or.setState("状态1");
- display(or);
-
- taker.setMemento(or.createMemento());
- or.setState("状态2");
- display(or);
- System.out.println("从备忘录恢复状态....");
- or.restoredFromMemento(taker.getMemento());
- display(or);
- }
-
- public static void display(Originator or){
- System.out.println("当前状态:"+or.getState());
- }
- }
-
-
-
-
- class Originator{
- private String state;
-
-
-
-
- public Memento createMemento(){
- return new Memento(this);
- }
-
-
-
- public void restoredFromMemento(Memento m){
- this.state = m.getState();
- }
- public String getState(){
- return state;
- }
- public void setState(String state){
- this.state = state;
- }
- }
-
-
-
-
-
-
-
- class Memento{
- private String state;
-
- public Memento(Originator or){
- this.state = or.getState();
- }
- public String getState() {
- return state;
- }
- public void setState(String state) {
- this.state = state;
- }
- }
-
-
-
-
- class Caretaker{
- private Memento memento;
-
- public Memento getMemento() {
- return memento;
- }
- public void setMemento(Memento memento) {
- this.memento = memento;
- }
- }
运行结果:
- 当前状态:状态1
- 当前状态:状态2
- 从备忘录恢复状态....
- 当前状态:状态1
四、模式优缺点
优点:
1、保持封装边界。备忘录可以避免暴露一些只应由原发器管理却又必须存储在原发器之外的信息(原发器的某个或某些临时状态)。通过备忘录将原发器Originator内部信息对其他对象屏蔽起来,从而保持了封装边界。
2、简化了原发器。备忘录模式通过将原发器不同的内部状态版本封装到对应的备忘录中,并将这些备忘录对象的存储交给负责人来简化原发器的设计和实现。
3、提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。当新的状态无效或者出现错误时,可以使用暂时存储起来的备忘录将状态复原。
缺点:
1、某些情况下使用备忘录代价会很高。如果原发器在生成备忘录时必须拷贝并存储大量的信息,或客户非常频繁地创建备忘录和恢复原发器状态,可能会导致非常大的开销,这些情况下不适合使用备忘录模式。
2、维护备忘录的潜在代价。由于系统不知道维护备忘录的多少,所以可能会导致存储大量的备忘录对象。这可以通过限制系统存储备忘录对象的数量来解决。另外系统要时刻防止其他对象修改备忘录状态,增加系统设计的复杂性。