设计模式实践之《二》:备忘录模式
使用场合
有时我们有这样的需求,一个对象在执行一系列操作的过程中,可能会为了防止因操作失败而致使前面所做的一切白费或是其他原因,需要对执行过程中的状态进行保存。然而该复杂对象的状态中的内容又不希望被除它之外的任何对象修改(即使该状态可能会保存在外部对象中),这个时候就需要使用备忘录模式。
我们还是先来看看UML:
我们定义一个接口,该接口不对外提供任何方法和属性,状态类实现该接口,这样任何的到该接口的类都不能修改到接口的内部信息。为了使状态类的内容只能被类A编辑,不能被其他类修改,这个时候我们需要把状态类定义成类A的内部类。
看到了吧,这样我们可以大胆地将类A的状态类转换成接口放到外部去存储。当类A需要状态信息的时候,将需要使用的状态类接口拿给类A,然后将接口转换成状态类进行状态信息的存取操作。
使用案例
我门有这样一个例子,玩RPG游戏的人都应该熟悉其中的人物需要通过不断的修炼来升级,假设我们没有将人物的状态保存在数据库或其它的持久化存储里面,数据全在内存。这个时候对于一个人物的状态只有人物本身可以修改,并且在玩家玩累了的时候可以将该人物状态放在外部某个地方保存,以便再次玩时恢复状态到保存时状态。但是保存在外部的状态又不能被别的对象所修改(能修改的话,就可能存在作弊)。所以,我们需要使用备忘录模式来达到我们的目的。
Work类中有这样的规则:每执行一次work操作,其Money的值加一,当Money值达到10,Level值增加一,呵呵,看起来规则也的确简单,但是要想Level增加只有老老实实的Work,除此之外可是没办法修改Worker状态的。
OK,我们还是来看看代码:
状态接口
using System;2
using System.Collections.Generic;3
using System.Text;4

5
namespace MemontoDemo6
{7
public interface IState8
{9
string ID { get;}10
int Money { get;}11
int Level { get;}12

13
IState Clone();14
}15
}16

Worker类,其中包含WorkState类
using System;2
using System.Collections.Generic;3
using System.Text;4

5
namespace MemontoDemo6
{7
public class Worker8
{9
private WorkState m_state = null;10
private string m_id = "007";11

12
public Worker(string id)13
{14
this.m_id = id;15
m_state = new WorkState(this.m_id);16
}17

18
public IState State { get { return this.m_state; } }19
20
/// <summary>21
/// 执行动作,更改状态22
/// </summary>23
public void Work()24
{25
this.m_state.Money++;26
if (this.m_state.Money % 10 == 0 && this.m_state.Money >= 10)27
this.m_state.Level++;28
}29

30
/// <summary>31
/// 恢复对象状态32
/// </summary>33
/// <param name="state"></param>34
public void Restore(IState state)35
{36
WorkState ImportState = (WorkState)state;37
this.m_state.Level = ImportState.Level;38
this.m_state.Money = ImportState.Money;39
}40

41
/// <summary>42
/// 实现了状态接口的类43
/// </summary>44
private class WorkState : IState45
{46
private string m_id = "";47
private int m_money = 0;48
private int m_level = 0;49

50
public WorkState(string id)51
{52
this.m_id = id;53
}54

55
public string ID56
{ get { return this.m_id; } }57

58
public int Money59
{60
get { return m_money ; }61
set { m_money = value; }62
} 63

64
public int Level65
{66
get { return m_level; }67
set { m_level = value; }68
}69

70
public IState Clone()71
{72
WorkState state = new WorkState(this.m_id);73
state.m_money = this.m_money;74
state.m_level = this.m_level;75
return (IState)state;76
}77
}78
}79
}80

Storage类
using System;2
using System.Collections;3
using System.Collections.Generic;4
using System.Text;5

6
namespace MemontoDemo7
{8
public class Storage9
{10
private ArrayList m_arrList = new ArrayList();11

12
public void Add(IState state)13
{14
this.m_arrList.Add(state);15
}16

17
public void Remove(IState state)18
{19
this.m_arrList.Remove(state);20
}21
22
/// <summary>23
/// 获取某个状态对象24
/// </summary>25
/// <param name="id"></param>26
/// <returns></returns>27
public IState GetState(string id)28
{29
foreach (object obj in m_arrList)30
{31
IState state = (IState)obj;32
if (state.ID == id)33
{34
return state;35
}36
}37
return null;38
}39
}40
}41

外部访问代码
using System;2
using System.Collections.Generic;3
using System.Windows.Forms;4

5
namespace MemontoDemo6
{7
public class Program8
{9
private static Storage s_storage = new Storage();10

11
/// <summary>12
/// The main entry point for the application.13
/// </summary>14
[STAThread]15
static void Main(string[] args)16
{17
//Application.EnableVisualStyles();18
//Application.SetCompatibleTextRenderingDefault(false);19
//Application.Run(new Form1());20
Worker worker = new Worker("NewWorker");21
Console.WriteLine("开始状态");22
Console.WriteLine(" Money:" + worker.State.Money);23
Console.WriteLine(" Level:" + worker.State.Level);24
for (int i = 0; i < 15;i++ )25
worker.Work();26

27
Console.WriteLine("工作一段时间后");28
Console.WriteLine(" Money:" + worker.State.Money);29
Console.WriteLine(" Level:" + worker.State.Level);30

31
s_storage.Add(worker.State.Clone());32

33
//使得对象状态可以在新对象中得到恢复34
Worker SecondUseWorker = new Worker("NewWorker");35
SecondUseWorker.Restore(s_storage.GetState("NewWorker"));36
Console.WriteLine("");37
Console.WriteLine("恢复状态后的Worker");38
Console.WriteLine(" Money:" + SecondUseWorker.State.Money);39
Console.WriteLine(" Level:" + SecondUseWorker.State.Level);40

41
Console.WriteLine("Print any key to continue
");42
Console.ReadLine();43
}44
}45
}好了,这是一个很简单的例子,和现实中比起来有太多的不足了,但是我门只要找到这个示例关注点,而这个关注点又恰恰存在使用备忘录模式的理由(或者说是将该模式做为其后选方案的理由),那么就达到了使用这个示例的目的了。



浙公网安备 33010602011771号