备忘录模式
在不违反封装的原则下,获取一个对象的内部状态并保留在外部,让该对象可以在日后恢复到原先保留时的状态。
备忘录模式的定义
如果以“游戏存盘”的功能来解释备忘录模式的定义,会更简单些,也就是在不增加各个游戏系统成员的“存取”方法的前提之下,存盘功能要能够获取各个游戏系统内部需要保存的信息,然后在游戏重新开始时,再将记录读取,并重新设置给各个游戏的系统。
备忘录模式的概念,是让有记录保存需求的类,自行产生要保存的数据,外界完全不用了解这些记录产生的过程及来源。另外,也让类自己从之前保存数据中找回信息,自行重设类的状态。
参与者说明如下:
- Originator(记录拥有者)
- 拥有记录的类,内部有成员或记录需要被存储。
- 会自动将要保存的记录产生出来,不必提供存储内部状态的方法。
- 会自动将数据从之前的保存记录中取回,并恢复到之前的状态。
- Memento(记录保存者)
- 负责保存 Originator(记录拥有者)的内部信息
- 无法获取 Originator(记录拥有者)的信息,必须由 Originator(记录拥有者)主动设置和读取
- Caretaker(管理记录保存者)
- 管理 Originator(记录拥有者)产生出来的 Memento(记录保存者)
- 可以增加对象管理容器来保存多个 Memento(记录保存者)
具体实现
// 存放Originator物件的內部狀態
public class Memento
{
string m_State;
public string GetState()
{
return m_State;
}
public void SetState(string State)
{
m_State = State;
}
}
// 需要儲存內容資訊
public class Originator
{
string m_State; // 狀態,需要被保存
public void SetInfo(string State)
{
m_State = State;
}
public void ShowInfo()
{
Debug.Log("Originator State:" + m_State);
}
// 產生要儲存的記錄
public Memento CreateMemento()
{
Memento newMemento = new Memento();
newMemento.SetState(m_State);
return newMemento;
}
// 設定要回復的記錄
public void SetMemento(Memento m)
{
m_State = m.GetState();
}
}
// 保管所有的Memento
public class Caretaker
{
Dictionary<string, Memento> m_Memntos = new Dictionary<string, Memento>();
// 增加
public void AddMemento(string Version, Memento theMemento)
{
if (m_Memntos.ContainsKey(Version) == false)
m_Memntos.Add(Version, theMemento);
else
m_Memntos[Version] = theMemento;
}
// 取回
public Memento GetMemento(string Version)
{
if (m_Memntos.ContainsKey(Version) == false)
return null;
return m_Memntos[Version];
}
}
成就记录保存的功能设计
参与者说明:
- AchievementSystem:成就系统拥有多项成就记录需要被存储,所以提供CreateSaveData方法让外界获取“存盘记录”,并利用SetSaveData方法将“之前存储的成就记录”回存。
- AchievementSaveData:记录成就系统中需要被存盘的成就记录,并实现Unity3D中的数据保存功能。
- PBaseDefenseGame:配合游戏启动和关闭,适时地调用成就系统的CreateSaveData、SetSaveData方法,来实现成就记录的保存和读取。
具体实现
// 成就記錄存檔
public class AchievementSaveData
{
// 成就要存檔的資訊
public int EnemyKilledCount { get; set; }
public int SoldierKilledCount { get; set; }
public int StageLv { get; set; }
public AchievementSaveData()
{
}
public void SaveData()
{
PlayerPrefs.SetInt("EnemyKilledCount", EnemyKilledCount);
PlayerPrefs.SetInt("SoldierKilledCount", SoldierKilledCount);
PlayerPrefs.SetInt("StageLv", StageLv);
}
public void LoadData()
{
EnemyKilledCount = PlayerPrefs.GetInt("EnemyKilledCount", 0);
SoldierKilledCount = PlayerPrefs.GetInt("SoldierKilledCount", 0);
StageLv = PlayerPrefs.GetInt("StageLv", 0);
}
}
// 成就系統
public class AchievementSystem : IGameSystem
{
private AchievementSaveData m_LastSaveData = null; // 最後一次的存檔資訊
// 記錄的成就項目
private int m_EnemyKilledCount = 0;
private int m_SoldierKilledCount = 0;
private int m_StageLv = 0;
public AchievementSystem(PBaseDefenseGame PBDGame) : base(PBDGame)
{
Initialize();
}
//
public override void Initialize()
{
base.Initialize();
// 註冊相關觀測者
m_PBDGame.RegisterGameEvent(ENUM_GameEvent.EnemyKilled, new EnemyKilledObserverAchievement(this));
m_PBDGame.RegisterGameEvent(ENUM_GameEvent.SoldierKilled, new SoldierKilledObserverAchievement(this));
m_PBDGame.RegisterGameEvent(ENUM_GameEvent.NewStage, new NewStageObserverAchievement(this));
}
// 增加Enemy陣亡數
public void AddEnemyKilledCount()
{
//Debug.Log ("AddEnemyKilledCount");
m_EnemyKilledCount++;
}
// 增加Soldier陣亡數
public void AddSoldierKilledCount()
{
//Debug.Log ("AddSoldierKilledCount");
m_SoldierKilledCount++;
}
// 目前關卡
public void SetNowStageLevel(int NowStageLevel)
{
//Debug.Log ("SetNowStageLevel");
m_StageLv = NowStageLevel;
}
// 產生存檔
public AchievementSaveData CreateSaveData()
{
AchievementSaveData SaveData = new AchievementSaveData();
// 設定新的高分者
SaveData.EnemyKilledCount = Mathf.Max(m_EnemyKilledCount, m_LastSaveData.EnemyKilledCount);
SaveData.SoldierKilledCount = Mathf.Max(m_SoldierKilledCount, m_LastSaveData.SoldierKilledCount);
SaveData.StageLv = Mathf.Max(m_StageLv, m_LastSaveData.StageLv);
return SaveData;
}
// 設定舊的存檔
public void SetSaveData(AchievementSaveData SaveData)
{
m_LastSaveData = SaveData;
}
// 儲存記錄
/*public void SaveData()
{
PlayerPrefs.SetInt("EnemyKilledCount" ,m_EnemyKilledCount);
PlayerPrefs.SetInt("SoldierKilledCount" ,m_SoldierKilledCount);
PlayerPrefs.SetInt("StageLv" ,m_StageLv);
}
// 取回記錄
public void LoadData()
{
m_EnemyKilledCount = PlayerPrefs.GetInt("EnemyKilledCount",0);
m_SoldierKilledCount= PlayerPrefs.GetInt("SoldierKilledCount",0);
m_StageLv = PlayerPrefs.GetInt("StageLv",0);
}*/
}
public class PBaseDefenseGame
{
....
// 存檔
private void SaveData()
{
AchievementSaveData SaveData = m_AchievementSystem.CreateSaveData();
SaveData.SaveData();
}
// 取回存檔
private AchievementSaveData LoadData()
{
AchievementSaveData OldData = new AchievementSaveData();
OldData.LoadData();
m_AchievementSystem.SetSaveData( OldData );
return OldData;
}
}
使用备忘录模式的优点
再运用备忘录模式之后,记录成就的功能就从成就系统中独立出来,让专职的AchievementSaveData类负责存盘的工作,至于AchievementSaveData类该怎么实现存盘功能,成就系统也不必知道。并且成就系统本身也保留封装性,不必对外开放过多的存取函数来获取内部的状态,信息的设置和恢复也都在成就系统内部完成。
备忘录模式的应用
游戏服务器常常需要针对执行性能进行分析及追踪,所以要定期地让各个系统产生日志,汇报各个游戏系统当前的执行情况,如内存的使用、执行时占用的事件、数据存取的频率等。要让系统日志功能更有弹性的话,可以使用备忘录模式让各个游戏系统产生要定期汇报的信息,并将信息内容的产生交给各个游戏系统,而日志系统只负责存储记录。