备忘录模式:在不破坏封装性得到前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将对象恢复到原先保存的状态
在理解代码的过程中是比较简单的一种,而且他的应用也很广泛。比如我们在玩象棋的时候需要悔棋,浏览网页的时候需要后退等等都是备忘录模式的应用。看了《大话设计模式》中是以一个游戏的例子来讲解得很通俗易懂。比如我们在打boss,但是在打得过程中如果打不过需要重新来过,我们就希望在打boss之前保存进度。如果打不过我们还可以恢复进度。
结构中的三个角色:
第一个:Originator(发起人)-GameRole:负责创建一个备忘录Memento;作用是记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。(发起人可以根据需要决定备忘录存储自己的那些内部状态)
GameRole中就需要有保存角色状态方法和恢复角色状态方法
第二个:Memento(备忘录)-RoleMemento:负责存储发起人Originator对象的内部状态;并且可以防止Originator以外的其他对象访问备忘录;RoleMemento类中需要存储GameRole对象中需要存储的内部状态并且设置成为私有性来避免其他的对象访问备忘录
RoleMemento中需要有角色需要保存的状态
Memento有两个接口:
1. Caretaker只能看到备忘录的窄接口:负责将备忘录传递给其他对象。
2. Originator看到备忘录的宽接口:允许它访问返回到先前状态所需要的所有数据
第三个:Caretaker(管理者)-RoleCaretaker:负责备忘录Memento。不能对Memento的内容进行访问或者操作
RoleCaretaker需要创建一个RoleMemento属性来完成对他的访问和设置
UML图形:
综上我理解的这个模式实现的过程是:备忘录将存储的功能实现但是通过管理者和发起者访问Memento来完成存储功能
代码实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 备忘录模式
{
//创建游戏角色的类
//包括三个属性 三个方法
//体力 攻击力 防御力三个属性
//状态显示 初始状态 战斗 三个方法
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 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;
}
//新增“保存角色状态”方法,游戏角色的三个状态之通过实例化“角色状态存储箱”返回
//保存角色状态
//保存角色方法---实例化出来一个RoleMemento(这个RoleMemento拥有角色此时的状态)
public RoleStateMemennto SaveState()
{
return (new RoleStateMemennto(vit, atk, def));
}
//新增“恢复角色状态”方法,可将外部的“角色状态存储箱”中的状态值恢复给游戏角色
//恢复角色状态
//恢复角色状态方法---传入存储箱对象,将存储箱中的内容传给当前的角色---从而完成恢复数据的任务
public void RecoveryState(RoleStateMemennto memento)
{
this.atk = memento.Attack;
this.vit = memento.Vitality;
this.def = memento.Defense;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 备忘录模式
{
//角色状态存储箱类
//需要保存的内部状态:体力atk 攻击力vit 防御力def
//目的:将需要保存的内部状态放在备忘录类中
class RoleStateMemennto
{
//将需要存储的内部状态设置成为私有性
//完成防止GameRole以外的其他对象访问备忘录中存储的状态
private int atk;
private int vit;
private int def;
//将三个属性存入状态存储箱中
//通过构造函数给三个属性设置初始值
public RoleStateMemennto (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; }
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 备忘录模式
{
//角色状态管理者
//只有一个属性---角色存储箱
//管理者的作用:负责备忘录Memento
//完成的任务:不能对Memento的内容进行访问或者操作--封装Memento
class RoleStateCaretaker
{
private RoleStateMemennto memento;
public RoleStateMemennto Memento
{
get { return memento; }
set { memento = value; }
}
}
}
客户端代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 备忘录模式
{
class Program
{
static void Main(string[] args)
{
GameRole lixiyao = new GameRole();
//lixiaoyao在大战boss前的初始状态
lixiyao.GetInitState();
lixiyao.StateDisplay();
//保存进度方法
//具体的做法:首先实例角色管理者---目的是设置存储箱这个属性来完成封装Memento的任务(客户端不必访问Memento)
//将需要保存的状态封装在Memento中,因此我们并不知道保存了那些具体的角色数据
RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
//然后为Memento属性赋值----完成保存进度的任务
// lixiyao.SaveState()方法记录的是此时角色GameRole(lixiyao)的状态
//所以赋值完成的任务是:将此时lixiyao的状态赋给了stateAdmin.Memento这个属性
//最终就可以保存进度
stateAdmin.Memento = lixiyao.SaveState();
//大战boss
lixiyao.Fight();
lixiyao.StateDisplay();
//恢复之前的状态
//具体做法:GameRole(发起者)调用恢复状态的方法
//角色调用恢复数据方法--将上面管理者的Memento属性作为参数传入
//从而将大战boss之前lixiyao的状态重新赋给了lixoyao
lixiyao.RecoveryState(stateAdmin.Memento);
lixiyao.StateDisplay();
//整个过程就是通过RoleCaretaker(管理者)的Memento属性和GameRole(发起者)调用两个方法来完成的
Console.Read();
}
}
}