18. 备忘录模式
约 1170 字大约 4 分钟
2026-03-13
定义
备忘录(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
人话:备忘录模式就像我们在玩游戏时的 存档功能。在游戏过程中,玩家可能已经打到了某一关,获得了一些装备、金币和经验值。如果突然游戏失败或者想重新尝试之前的某个状态,就希望能 恢复到之前保存的进度。
如果游戏程序每次都手动记录各种数据,比如角色等级、金币数量、装备信息等,并且在需要恢复时再一条条重新设置,这样不仅麻烦,还容易出错。这在软件中就属于 状态管理混乱、实现细节暴露过多。
而使用备忘录模式之后,就相当于游戏提供了 存档点。当玩家点击“保存游戏”时,游戏会把当前角色的所有重要状态(比如等级、金币、装备等)打包成一个 存档(备忘录) 保存起来。当玩家想回到之前的进度时,只需要读取这个存档,就可以把角色恢复到当时的状态。
在软件中也是一样:对象在需要保存状态时,会创建一个 备忘录对象 来记录当前状态,而 管理者(Caretaker) 负责保存这个备忘录。当需要恢复时,只要把备忘录重新交给原对象,就可以恢复到之前的状态,而不需要关心内部具体实现细节。
备忘录模式(Memento)结构图
Originator类——发起人:
// 发起人(Originator)
class Originator
{
// 需要保存的属性,可能有多个
private string state;
public string State
{
get { return state; }
set { state = value; }
}
// 创建备忘录,将当前需要保存的信息导入
public Memento CreateMemento()
{
return new Memento(state);
}
// 恢复备忘录,将 Memento 导入并恢复数据
public void SetMemento(Memento memento)
{
state = memento.State;
}
// 显示当前状态
public void Show()
{
Console.WriteLine("State = " + state);
}
}Memento类——备忘录:
// 备忘录(Memento)
class Memento
{
private string state;
// 构造方法,将相关数据导入
public Memento(string state)
{
this.state = state;
}
// 需要保存的数据属性
public string State
{
get { return state; }
}
}Caretaker类——管理者:
// 管理者(Caretaker)
class Caretaker
{
private Memento memento;
// 得到或设置备忘录
public Memento Memento
{
get { return memento; }
set { memento = value; }
}
}客户端代码:
static void Main(string[] args)
{
// Originator 初始状态
Originator o = new Originator();
o.State = "On";
o.Show();
// 保存状态
Caretaker c = new Caretaker();
c.Memento = o.CreateMemento();
// 改变状态
o.State = "Off";
o.Show();
// 恢复原来的状态
o.SetMemento(c.Memento);
o.Show();
Console.Read();
}把要保存的细节给封装在了Memento中了,哪一天要更改保存的细节也不用影响客户端了。
Memento模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator可以根据保存的Memento信息还原到前一状态。
命令模式也有实现类似撤销的作用?如果在某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令模式可以使用备忘录模式来存储可撤销操作的状态。有时一些对象的内部信息必须保存在对象以外的地方,但是必须要由对象自己读取,这时,使用备忘录可以把复杂的对象内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。
最大的作用还是在当角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原这个作用。
要注意,备忘录模式也是有缺点的,角色状态需要完整存储到备忘录对象中,如果状态数据很大很多,那么在资源消耗上,备忘录对象会非常耗内存。
