备忘录模式(Memento)

First Post:

Last Update:

备忘录模式的定义与特点

备忘录(Memento)模式的定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。

备忘录模式减少了细节的暴露

例如,将许多实现细节写在了客户端当中,这是相当不可取的。

备忘录模式结构图

备忘录模式类图

备忘录模式成员分析

Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复状态。Originator可根据需求决定Memento存储Originator的哪些内部状态。

Memento(备忘录):负责存储Originator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento。备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。

Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。

备忘录模式代码结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
发起者类(Originator)
Class Originator
{
//需要保存的属性,可以有多个
Private string state;
Public string State
{
get{ return state; }
set{ state = value; }
}

//创建备忘录,将当前需要保存的信息导入并实例化出一个Memento对象
Public Memento CreateMemento()
{
Retrun new Memento(state);
}

//恢复备忘录,将Memento导入并将相关数据恢复
Public SetMemento(Memento memento)
{
State = memento.state;
}
//public void show()
//{
//展示数据
//}
}

//备忘录类
Class Memento
{
Private string state;
//构造方法,将相关数据导入
Public Memento(string state)
{
This.state = state;
}
//需要保存的数据属性,可以有多个
Public string State
{
get{ return state; }
}
}

//管理者类
Class Caretaker
{
Private Memento memento;
//设置或得到备忘录
Public Memento Memento
{
get{ return memento; }
set{ memento = value; }
}
}

//客户端代码
Originator p = new Originator( );
p.State = "On";
p.show();

//保存状态
Caretaker c = new Caretaker( );
C.memento = o.CreateMemento( );
//这隐藏了Originator的实现细节

//改变了p的状态
p.state = "Off";
p.show( );

//恢复成之前的状态
c.SetMemento(c.memento);
p.show( );

备忘录模式总结

备忘录模式是一种对象行为型模式。

优点

  • 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
  • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。(备忘录模式将要保存的细节都封装在了Memento中,当要更改保存的细节时也不用再影响客户端了。)
  • 简化了 发起人 类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。

缺点:

  • 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。

意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

何时使用:很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有”后悔药”可吃。

如何解决:通过一个备忘录类专门存储对象状态。
关键代码:客户不与备忘录类耦合,与备忘录管理类耦合。
应用实例

  1. 后悔药。

  2. 打游戏时的存档。

  3. Windows 里的 ctrl + z。

  4. IE 中的后退。

  5. 数据库的事务管理。

使用场景:

  • 需要保存/恢复数据的相关状态场景。

  • 提供一个可回滚的操作。

注意事项:

  • 为了符合迪米特原则,还要增加一个管理备忘录的类。

  • 为了节约内存,可使用原型模式+备忘录模式。