Memento备忘录模式
有的时候需要对一个对象的状态进行恢复,象撤消按钮一样.本例中一个长方形对象,用四个数字记录长方形的状态,当变化发生的时候,有一个机制在变化之前记录状态.以下的关键都在GraphicsSystem中也就是元发器进行管理操作的.
硬编码,虽然实现了需求,但是将记录对象暴露给外部,调用者可以修改它:
HardCode
using System;
class RecTangle : ICloneable
{
int x;
int y;
int Width;
int Height;
public void SetValue(RecTangle r)
{
this.x = r.x;
this.y = r.y;
this.Width = r.Width;
this.Height = r.Height;
}
public object Clone()
{
return this.MemberwiseClone();
}
public RecTangle(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
自身操作部分#region 自身操作部分
public void MoveTo
{ }
public void ChangeWidth(int width)
{ }
public void ChangeHeight(int height)
{ }
public void Draw(Graphic graphic)
{ }
#endregion
}
class GraphicsSystem
{
//元发器对象
//有必要对自身状态进项保存,然后再某个点处又需要恢复的对象
RecTangle r = new RecTangle(0,0,10,10);
//备忘录对象-----保存元发器对象的状态,但是不提供对象支持的操作
RecTangle rSaved = new RecTangle(0, 0, 10, 10);
public static void Process()
{
RecTangle rSaved = r.Clone();
//..
}
//将原来保存的值再传递回来
public void Saved_Click(object sender,EventArgs e)
{
r.SetValue(rSaved);
}
}
using System;
class RecTangle : ICloneable
{
int x;
int y;
int Width;
int Height;
public void SetValue(RecTangle r)
{
this.x = r.x;
this.y = r.y;
this.Width = r.Width;
this.Height = r.Height;
}
public object Clone()
{
return this.MemberwiseClone();
}
public RecTangle(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
自身操作部分#region 自身操作部分
public void MoveTo
{ }
public void ChangeWidth(int width)
{ }
public void ChangeHeight(int height)
{ }
public void Draw(Graphic graphic)
{ }
#endregion
}
class GraphicsSystem
{
//元发器对象
//有必要对自身状态进项保存,然后再某个点处又需要恢复的对象
RecTangle r = new RecTangle(0,0,10,10);
//备忘录对象-----保存元发器对象的状态,但是不提供对象支持的操作
RecTangle rSaved = new RecTangle(0, 0, 10, 10);
public static void Process()
{
RecTangle rSaved = r.Clone();
//..
}
//将原来保存的值再传递回来
public void Saved_Click(object sender,EventArgs e)
{
r.SetValue(rSaved);
}
}
Memento的一种方式,编码复杂,但是给调用者的是一个窄的接口,不能操作记录对象:
Memento1
using System;
class RecTangle : ICloneable
{
int x;
int y;
int Width;
int Height;
public void SetValue(RecTangle r)
{
this.x = r.x;
this.y = r.y;
this.Width = r.Width;
this.Height = r.Height;
}
public object Clone()
{
return this.MemberwiseClone();
}
public RecTangle(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
public void MoveTo
{
}
public void ChangeWidth(int width)
{ }
public void ChangeHeight(int height)
{ }
public void Draw(Graphic graphic)
{ }
public RectangleMemento CreateMemento()
{
RectangleMemento rm = new RectangleMemento();
rm.SetState(this.x, this.y, this.Width, this.Height);
return rm;
}
public void SetMemento(RecTangle rm)
{
this.x = rm.x;
this.y = rm.y;
this.Width = rm.Width;
this.Height = rm.Height;
}
}
//仅仅作为一个状态存储的对象,对于本例来说就是4个数字
public class RectangleMemento
{
internal int x;
internal int y;
internal int Width;
internal int Height;
internal void SetState(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
}
//GraphicsSystem 处于另外的程序集中
class GraphicsSystem
{
//元发器对象
//有必要对自身状态进项保存,然后再某个点处又需要恢复的对象
RecTangle r = new RecTangle(0, 0, 10, 10);
//备忘录对象-----保存元发器对象的状态,但是不提供对象支持的操作
RectangleMemento rSaved = new RectangleMemento();
//用rSaved保存元发状态
public static void Process()
{
RecTangle rSaved = rSaved.CreateMemento();
//..
}
//回调
public void Saved_Click(object sender, EventArgs e)
{
r.SetMemento(rSaved);
}
}
using System;
class RecTangle : ICloneable
{
int x;
int y;
int Width;
int Height;
public void SetValue(RecTangle r)
{
this.x = r.x;
this.y = r.y;
this.Width = r.Width;
this.Height = r.Height;
}
public object Clone()
{
return this.MemberwiseClone();
}
public RecTangle(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
public void MoveTo
{
}
public void ChangeWidth(int width)
{ }
public void ChangeHeight(int height)
{ }
public void Draw(Graphic graphic)
{ }
public RectangleMemento CreateMemento()
{
RectangleMemento rm = new RectangleMemento();
rm.SetState(this.x, this.y, this.Width, this.Height);
return rm;
}
public void SetMemento(RecTangle rm)
{
this.x = rm.x;
this.y = rm.y;
this.Width = rm.Width;
this.Height = rm.Height;
}
}
//仅仅作为一个状态存储的对象,对于本例来说就是4个数字
public class RectangleMemento
{
internal int x;
internal int y;
internal int Width;
internal int Height;
internal void SetState(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
}
//GraphicsSystem 处于另外的程序集中
class GraphicsSystem
{
//元发器对象
//有必要对自身状态进项保存,然后再某个点处又需要恢复的对象
RecTangle r = new RecTangle(0, 0, 10, 10);
//备忘录对象-----保存元发器对象的状态,但是不提供对象支持的操作
RectangleMemento rSaved = new RectangleMemento();
//用rSaved保存元发状态
public static void Process()
{
RecTangle rSaved = rSaved.CreateMemento();
//..
}
//回调
public void Saved_Click(object sender, EventArgs e)
{
r.SetMemento(rSaved);
}
}
一种好的做法就是把需要记录状态的对象做成一个内存流进行保存:
MementoStream
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
/**//// <summary>
/// 序列化
/// </summary>
///
[Serializable]
class RecTangle : ICloneable
{
int x;
int y;
int Width;
int Height;
public RecTangle(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
public void MoveTo
{ }
public void ChangeWidth(int width)
{ }
public void ChangeHeight(int height)
{ }
public void Draw(Graphic graphic)
{ }
}
//GraphicsSystem 处于另外的程序集中
class GraphicsSystem
{
//元发器对象
//有必要对自身状态进项保存,然后再某个点处又需要恢复的对象
RecTangle r = new RecTangle(0, 0, 10, 10);
//备忘录对象-----保存元发器对象的状态,但是不提供对象支持的操作
//RectangleMemento rSaved = new RectangleMemento();
MemoryStream rSaved = new MemoryStream();
public static void Process()
{
//先序列化将状态作为rSaved保存下来
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(r, rSaved);
//然后做其它操作..
}
//触发恢复事件
public void Saved_Click(object sender, EventArgs e)
{
//反序列化
BinaryFormatter bf = new BinaryFormatter();
rSaved.Seek(0,SeekOrigin);
r = (RecTangle)bf.Deserialize(rSaved);
}
}
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
/**//// <summary>
/// 序列化
/// </summary>
///
[Serializable]
class RecTangle : ICloneable
{
int x;
int y;
int Width;
int Height;
public RecTangle(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.Width = width;
this.Height = height;
}
public void MoveTo
{ }
public void ChangeWidth(int width)
{ }
public void ChangeHeight(int height)
{ }
public void Draw(Graphic graphic)
{ }
}
//GraphicsSystem 处于另外的程序集中
class GraphicsSystem
{
//元发器对象
//有必要对自身状态进项保存,然后再某个点处又需要恢复的对象
RecTangle r = new RecTangle(0, 0, 10, 10);
//备忘录对象-----保存元发器对象的状态,但是不提供对象支持的操作
//RectangleMemento rSaved = new RectangleMemento();
MemoryStream rSaved = new MemoryStream();
public static void Process()
{
//先序列化将状态作为rSaved保存下来
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(r, rSaved);
//然后做其它操作..
}
//触发恢复事件
public void Saved_Click(object sender, EventArgs e)
{
//反序列化
BinaryFormatter bf = new BinaryFormatter();
rSaved.Seek(0,SeekOrigin);
r = (RecTangle)bf.Deserialize(rSaved);
}
}
泛型的记录,这里仅仅列出一个类的代码,其他应该与上面差别不大 :
泛啦
class GeneralMementor
{
MemoryStream rSaved = new MemoryStream();
public GeneralMemento(Factory factory)
{
rSaved = factory.CreateStream();
}
internal void SetState(object obj)
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(obj,rSaved);
}
internal object GetState()
{
BinaryFormatter bf = new BinaryFormatter();
rSaved.Seek(0,SeekOrigin);
object obj = (RecTangle)bf.Deserialize(rSaved);
return obj;
}
}
class GeneralMementor
{
MemoryStream rSaved = new MemoryStream();
public GeneralMemento(Factory factory)
{
rSaved = factory.CreateStream();
}
internal void SetState(object obj)
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(obj,rSaved);
}
internal object GetState()
{
BinaryFormatter bf = new BinaryFormatter();
rSaved.Seek(0,SeekOrigin);
object obj = (RecTangle)bf.Deserialize(rSaved);
return obj;
}
}