目录
一、什么是备忘录模式?
二、备忘录模式有什么优点吗?
2.1、封装状态:
2.2、实现撤销和恢复功能:
2.3、简化原始对象:
2.4、对用户友好的接口:
2.5、支持多次撤销:
2.6、实现历史记录:
2.7、灵活性和可扩展性:
2.8、解耦状态保存:
三、有什么缺点吗?
四、什么场合使用备忘录模式?
五、代码展示
5.1、发起人(Originator)类
5.2、备忘录(Memento)类
5.3、管理类(Caretaker)类
5.4、客户端
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
比如像我们平常使用的Ctrl+Z撤销操作、浏览器里面的回退操作、还有数据库的事务回滚、手机相册删除的照片可以恢复,这些都是让你吃“后悔药”的行为。体现了备忘录模式。
Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的那些内部状态。
Memento(备忘录):负责存储Originator对象的内部状态。
Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。
备忘录模式在一些需要实现撤销、恢复或历史记录功能的场景中非常有用。以下是备忘录模式的一些优点:
备忘录模式通过将对象的状态封装在备忘录对象中,避免了在原对象中暴露状态的细节。这有助于保持对象的封装性和数据隐私。
备忘录模式使得对象可以在不同的时间点保存其状态,并在需要时恢复到之前的某个状态。这为实现撤销和恢复功能提供了一种有效的机制。
通过将状态保存在备忘录中,原始对象不再需要维护多个历史状态,从而减轻了原始对象的负担,使其更加专注于核心业务逻辑。
备忘录模式将状态保存和恢复的逻辑封装在备忘录对象中,为用户提供了简单和一致的接口,用户无需关心内部实现细节。
备忘录模式可以保存多个状态快照,使得对象可以在不同的时间点进行多次撤销操作。
备忘录模式可以用于实现对象的历史记录,记录对象的不同状态变化,为审计和分析提供支持。
备忘录模式允许在不修改原始对象的情况下新增备忘录类型,从而提供了灵活性和可扩展性,适应不同的需求。
备忘录模式将状态保存和恢复的职责从原始对象中解耦,减少了原始对象的复杂性,使得代码更易于维护和理解。
资源消耗: 备忘录模式需要在备忘录对象中保存对象的状态,如果对象的状态较大或者状态变化频繁,可能会消耗较多的内存资源。这特别在需要保存多个历史状态时会更为显著。
效率问题: 在一些情况下,备忘录模式可能会导致性能问题。每次保存状态都需要创建一个备忘录对象,这涉及到对象的拷贝操作,而拷贝操作可能会耗费较多的时间。
复杂性增加: 备忘录模式引入了备忘录类,使得代码中涉及到更多的类和交互,从而增加了代码的复杂性。尤其是在需要保存多个对象的状态时,代码可能会变得更加繁琐。
封装破坏: 尽管备忘录模式通过封装对象的状态实现了信息隐蔽,但它也可能破坏了对象的一致性。因为备忘录对象需要访问原始对象的状态,可能会使得原始对象的一些私有属性暴露给外部。
状态一致性问题: 在某些情况下,备忘录模式可能会引入状态一致性问题。如果备忘录对象不正确地保存了对象的状态,或者在恢复状态时发生了错误,可能导致对象的状态不一致。
不适合大规模状态变化: 备忘录模式更适用于状态变化频率较低的场景。如果对象的状态变化非常频繁,可能会导致备忘录对象的数量急剧增加,从而增加了管理和维护的难度。
无法回滚外部资源: 如果对象的状态不仅仅包括内部数据,还包括外部资源的状态(例如数据库连接),备忘录模式可能无法正确地回滚外部资源的状态。
适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator可以根据保存的Memento信息还原到前一状态。
如果再某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令模式可以使用备忘录模式来存储可撤销操作的状态。
使用备忘录可以把负责的对象内部信息对其他的对象屏蔽起来。
当角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。
场景:游戏的某个场景,一游戏角色有生命力、攻击力、防御力等等数据,在打Boss前和后一定会不一样的,我们允许玩家如果感觉与Boss决斗的效果不理想可以让游戏回复到决斗前。
①、备忘录模式
class Originator
{
private string state; //成员变量
public string State //需要保存的属性
{
get { return state; }
set { state = value; }
}
//创建备忘录
public Memento CreateMemento()
{
//讲当前需要保存的信息导入并实例化出一个Memento对象
return (new Memento(state));
}
//恢复备忘录
public void SetMemento(Memento memento)
{
state = memento.State; //将Memento导入并将相关数据恢复
}
//显示数据
public void Show()
{
Console.WriteLine("State={0}", state);
}
}
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 o = new Originator(); //实例化一个发起人
o.State = "On"; //初始状态属性为“On”
o.Show(); //显示当前状态
Caretaker c = new Caretaker(); //创建一个管理者
//发起人创建一个备忘录,将创建的备忘录复制给管理者的属性
c.Memento = o.CreateMemento();
o.State = "Off"; //状态属性为“Off”
o.Show(); //显示当前状态
o.SetMemento(c.Memento); //管理者调用保存的数据赋值给发起人并恢复备忘录
o.Show(); //显示当前状态
Console.ReadKey();