初识
备忘录(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。把要保存的细节封装在一个类中,在保存此状态时,可以隐藏内部细节。 如要更改保存的细节,这样也不用对客户端进行改动了。
结构
角色:
- Originator类:负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态
- Memento类:负责存储Originator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento
- Caretaker类:负责保存好备忘录Memento
分析:如果不用Caretaker类,直接将设置备忘录的步骤放到Memento类,在客户端实例化备忘录类时就需要将状态作为参数传入备忘录。这里专门用一个Caretaker类来放备忘录内部状态,是为了将内部状态进行封装,不把细节暴露给客户端。
应用
当我们浏览网页时,使用快捷键Ctrl+z就可撤销到历史网页状态,相当于给你浏览的网页都做了快照,在你想翻看历史记录或者撤销操作的时候即可返回到历史界面。还有,我们在玩游戏时,打到关底了,剩一个大BOSS,这时,为了保险我们将进度保存一下,以免复活时之前玩的进度没有了。这都是典型的备忘录模式。
实现
class Program
{
static void Main(string[] args)
{
GameRole lixiaoyao = new GameRole();
lixiaoyao.GetInitState();
lixiaoyao.StateDisplay();
RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
stateAdmin.Memento = lixiaoyao.SaveState(); //保存状态
lixiaoyao.Fight();
lixiaoyao.StateDisplay();
lixiaoyao.RecoveryState(stateAdmin.Memento);//恢复状态
lixiaoyao.StateDisplay();
Console.Read();
}
}
class GameRole//游戏角色类
{
private int vit;
public int Vitality
{
get { return vit; }
set { vit = value; }
}
private int atk;
public int Attack
{
get { return atk; }
set { atk = value; }
}
private int def;
public int Defense
{
get { return def; }
set { def = value; }
}
public RoleStateMemento SaveState()//保存状态
{
return (new RoleStateMemento(vit, atk, def));
}
public void RecoveryState(RoleStateMemento memento)//恢复状态
{
this.vit = memento.Vitality;
this.atk = memento.Attack;
this.def = memento.Defense;
}
public void StateDisplay()//显示状态
{
Console.WriteLine("角色当前状态:");
Console.WriteLine("体力:{0}",this.vit);
Console.WriteLine("攻击力:{0}",this.atk);
Console.WriteLine("防御力:{0}",this.def);
Console.WriteLine("");
}
public void GetInitState()//初始状态
{
this.vit = 100;
this.atk = 100;
this.def = 100;
}
public void Fight()//战斗
{
this.vit = 0;
this.atk = 0;
this.def = 0;
}
}
class RoleStateMemento//角色状态存储箱
{
private int vit;
private int atk;
private int def;
public RoleStateMemento(int vit,int atk,int def)
{
this.vit = vit;
this.atk = atk;
this.def = def;
}
public int Vitality
{
get { return vit; }
set { vit = value; }
}
public int Attack
{
get { return atk; }
set { atk = value; }
}
public int Defense
{
get { return def; }
set { def = value; }
}
}
class RoleStateCaretaker//角色状态管理者类
{
private RoleStateMemento memento;
public RoleStateMemento Memento
{
get { return memento; }
set { memento = value; }
}
}
优点
- 提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用先前存储起来的备忘录将状态复原。
- 实现了信息的封装,一个备忘录对象是一种原发器对象的表示,不会被其他代码改动,这种模式简化了原发器对象,备忘录只保存原发器的状态,采用堆栈来存储备忘录对象可以实现多次撤销操作,可以通过在负责人中定义集合对象来存储多个备忘录。
缺点
- 资源消耗过大,如果类的成员变量太多,就不可避免占用大量的内存,而且每保存一次对象的状态都需要消耗内存资源,如果知道这一点大家就容易理解为什么一些提供了撤销功能的软件在运行时所需的内存和硬盘空间比较大了。
适用场景
- 保存一个对象在某一个时刻的状态或部分状态,这样以后需要时它能够恢复到先前的状态。
- 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过负责人可以间接访问其内部状态。