Memento 备忘录模式(行为型模式)

对象状态的回溯

对象状态的变化无端,如何回溯、恢复对象在某个点的状态?

动机(Motivation)

在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些共有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。

如何实现对象状态良好保存与恢复?同时又不会因而破坏对象本身的封装性。

意图(Intent)

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。——《设计模式》GoF

示例代码

    public class Rectangle:ICloneable
{
private int x;
private int y;
private int width;
private 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(Point p)
{
//...
} public void ChangeWidth(int width)
{
//...
} public void ChangeHeight(int height)
{
//...
} public void Draw(Graphic graphic)
{
//...
} public object Clone()
{
return this.MemberwiseClone();
}
} class GraphicSystem
{
//原发器对象
//有必要对自身的状态进行保存,然后在某个点处又需要恢复内部状态
Rectangle r=new Rectangle(,,,); //备忘录对象
//保存原发器对象内部状态,但是不提供原发器对象支持的操作
Rectangle rSaved=new Rectangle(,,,);//不符合备忘录对象的要求 public void Process()
{
rSaved = r.Clone() as Rectangle;
}
}

由于rSaved不应该提供原发器对象支持的操作,所以它不符合备忘录对象的要求。不符合单一职责原则。

解决方案一:

    public class Rectangle
{
private int x;
private int y;
private int width;
private 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(Point p)
{
//...
} 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 SetMento(RectangleMemento rm)
{
this.x = rm.x;
this.y = rm.y;
this.width = rm.width;
this.height = rm.height;
}
} 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;
}
} class GraphicSystem
{
//原发器对象
//有必要对自身的状态进行保存,然后在某个点处又需要恢复内部状态
Rectangle r=new Rectangle(,,,); //备忘录对象
//保存原发器对象内部状态,但是不提供原发器对象支持的操作
RectangleMemento rSaved = new RectangleMemento(); public void Process()
{
rSaved = r.CreateMemento();
}
}

解决方案二:通过序列化方式

   [Serializable]
  public class Rectangle
{
private int x;
private int y;
private int width;
private 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(Point p)
{
//...
} public void ChangeWidth(int width)
{
//...
} public void ChangeHeight(int height)
{
//...
} public void Draw(Graphic graphic)
{
//...
} }    //通用备忘录类
class GeneralMenento
{
MemoryStream rSaved = new MemoryStream(); internal void SetState(object obj)
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(rSaved, obj);
} internal object GetState()
{
BinaryFormatter bf = new BinaryFormatter();
rSaved.Seek(, SeekOrigin.Begin);
return bf.Deserialize(rSaved);
}
} class GraphicSystem
{
//原发器对象
//有必要对自身的状态进行保存,然后在某个点处又需要恢复内部状态
Rectangle r=new Rectangle(,,,); GeneralMenento rSaved = new GeneralMenento(); public void Process()
{
rSaved.SetState(r);
}
}

结构(Structure)

Memento模式的几个要点

  • 备忘录(Memento)存储原发器(Originator)对象内部状态,在需要时恢复原发器状态。Memento模式适用于“由原发器管理,却又必须存储在原发器之外的信息”。
  • 在实现Memento模式中,要防止原发器以外的对象访问备忘录对象。备忘录对象由两个接口,一个为原发器使用的宽接口,一个为其他对象使用的窄接口。
  • 在实现Memento模式时,要考虑拷贝对象状态的效率问题,如果对象开销较大,可以采用某种增量式改变来改进Memento模式。

转载请注明出处:

作者:JesseLZJ
出处:http://jesselzj.cnblogs.com

最新文章

  1. Oracle 超长字符串分割劈分
  2. python基础第四天(1)
  3. Object.create 函数 (JavaScript)
  4. [firefox+plug-n-hack]轻松地配置burpsuite代理https流量
  5. mac 功能修改。。。。
  6. javascript一些常用操作
  7. Redpine的Lite-Fi解决方案获Wi-Fi CERTIFIED认证
  8. checkbox复选框全选批量删除
  9. ubuntu 安装chrome浏览器
  10. java基础--动态代理实现与原理详细分析
  11. 批处理之 for/f 详解
  12. 源码中的哲学——通过构建者模式创建SparkSession
  13. 怎么让DIV在另一个DIV里靠底部显示?
  14. Mysql对用户的操作
  15. Unity Shader 基础(1): RenderType & ReplacementShader
  16. Python从菜鸟到高手(6):获取用户输入、函数与注释
  17. [算法专题] BST&AVL&RB-Tree
  18. BZOJ2351[BeiJing2011]Matrix——二维hash
  19. 负载均衡(Load Balancing)学习笔记(三)
  20. 如何利用RMAN Debug和10046 Trace来诊断RMAN问题?

热门文章

  1. 优化笔记:pfyhparopenfundinfotest_D_20140916.gz
  2. ceph journal更换位置
  3. linux grep日志查询
  4. Eclipse的基本使用
  5. sublime text 怎么浏览包
  6. 关于java中word转html
  7. Django的contenttypes应用、缓存相关
  8. CBV 验证装饰器的使用
  9. UNITY 画布的粗浅理解
  10. 06002001单例模式C#实现版本