备忘录(Memento)模式

来源:互联网 发布:手机系统更新软件 编辑:程序博客网 时间:2024/06/09 15:59

对象状态的回溯

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

1、动机
在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。
如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性。

2、意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

3、图

4、代码

v1.0

public 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 object Clone()
 {
  return this.MemberwiseClone();
 }

 public void SetValue( Rectangle r )
 {
  this.x = r.x;
  this.y = r.y;
  this.width = r.width;
  this.height = r.height;
 }

 public void MoveTo(Point p)
 {
  
 }

 public void ChangeWidth( int width )
 {
  
 }
 
 public void ChangeHeight( int height )
 {

 }

 public void Draw( Graphic graphic )
 {
  
 }
}

public class GraphicsSystem
{
 //原发器对象
 //有必要对自身状态进行保存,然后在某个点处又需要恢复内部状态人的对象
 Rectangle r = new Rectangle(0,0,10,10);
 
 //备忘录对象
 //保存原发器对象的状态,但是不提供原发器对象支持的操作
 Rectangle rSaved = new Rectangle(0,0,10,10);

 public void Process( )
 {
  rSaved = r.Clone();

  //....
 }

 public void Process( )
 {
  rSaved = r.Clone();

  //....
 }

 public void Saved_Click(object sender , EventAgrs e )
 {
  r.SetValue( rSaved );
 }
}
 

v2.0

public class Rectangle
{
 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(Point p)
 {
  
 }

 public void ChangeWidth( int width )
 {
  
 }
 
 public void ChangeHeight( int height )
 {

 }

 public void Draw( Graphic graphic )
 {
  
 }

 public RectangleMemento CreateMemonto()
 {
  RectangleMemento rm = new RectangleMemento();

  rm.SetState( this.x , this.y  , this.width , this.height);

  return tm;
 }

 public void SetMemento(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;
 }
}

//GraphicsSystem处于另外的程序集中
public class GraphicsSystem
{
 //原发器对象
 //有必要对自身状态进行保存,然后在某个点处又需要恢复内部状态人的对象
 Rectangle r = new Rectangle(0,0,10,10);
 
 //备忘录对象
 //保存原发器对象的状态,但是不提供原发器对象支持的操作
 RectangleMemento rSaved = new RectangleMemento ();

 public void Process( )
 {
  rSaved = r.CreateMemonto();

  //....
 }

 public void Process( )
 {
  rSaved = r.CreateMemonto();

  //....
 }

 public void Saved_Click(object sender , EventAgrs e )
 {
  r.SetMemento( rSaved );
 }
}

v3.0

[Serizable]
public class Rectangle
{
 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(Point p)
 {
  
 }

 public void ChangeWidth( int width )
 {
  
 }
 
 public void ChangeHeight( int height )
 {

 }

 public void Draw( Graphic graphic )
 {
  
 }

 public GeneralMemontor CreateMemonto()
 {
  GeneralMemontor gm = new RectangleMemento();

  gm.SetState( this );

  return gm;
 }

 public void SetMemento(GeneralMemontor  memento)
 {
  Rectangle r = (Rectangle)memento.GetState();

  this.x = r.x;
  this.y = r.y;
  this.width = r.width;
  this.height = r.height;
 }

}

class GeneralMemontor
{
 Stream rSaved;

 public GeneralMemontor(Factory factory)
 {
  rSaved = factory.CreateStream() ;
 }

 internal void SetState(object obj)
 {
  BinaryFomatter bf = new BinaryFomatter();
  bf.Serialize( obj , rSaved );
 }

 internal obj GetState()
 {
  BinaryFomatter bf = new BinaryFomatter();
  
  rSaved.Seek( 0 , Seek.Original );

  object obj = bf.DeSerialize( rSaved );

  return obj;
 }


}

public class GraphicsSystem
{
 //原发器对象
 //有必要对自身状态进行保存,然后在某个点处又需要恢复内部状态人的对象
 Rectangle r = new Rectangle(0,0,10,10);
 
 //备忘录对象
 //保存原发器对象的状态,但是不提供原发器对象支持的操作
 GeneralMemontor rSaved = new GeneralMemontor();

 public void Process( )
 {
  rSaved = r.CreateMemonto();

  //....
 }

 public void Process( )
 {
  rSaved = r.CreateMemonto();

  //....
 }

 public void Saved_Click(object sender , EventAgrs e )
 {
  r.SetMemento( rSaved );
 }
}

------------------------------------------------------------------------------------------------------------

白箱设计

public class Originator
{
 private string state;
  
 public Memento createMemento()
 {
  return new Memento( state );
 }

 public void restoreMemento( Memento memento )
 {
  this.state = memento.State;
 }

 public string State
 {
  get
  {
   return state;
  }
  set
  {
   state = value;
  }
 }
}

public class Memento
{
 private string state;
  
 public Memento( string state )
 {
  this.state = state;
 }

 public string State
 {
  get
  {
   return state;
  }
  set
  {
   state = value;
  }
 }
}

public class Caretaker
{
 private Memento memento;
  
 public Memento retrieveMemento()
 {
  return this.memento;
 }

 public void savaMemento( Memento memento )
 {
  this.memento = memento;
 }

}

public class Client
{
 private static Originator o = new Originator();
 private static Caretaker c = new Caretaker();

 public static void main(string[] args)
 {
  o.State = "On";

  //保存
  c.savaMemento( o.createMemento() );

  o.State = "Off";

  //恢复
  o.restoreMemento( c.retrieveMemento() );
 }
}

黑箱设计

public interface MementoIF
{

}

public class Originator
{
 private string state;
  
 public MementoIf createMemento()
 {
  return new Memento( this.state );
 }

 public void restoreMemento( MementoIf memento )
 {
  Memento aMemento = (Memento)memento
  this.state = aMemento.SavedState;
 }

 public string State
 {
  get
  {
   return state;
  }
  set
  {
   state = value;
  }
 }

 public class Memento : MementoIF
 {
  private string savedState;
  
  public Memento( string state )
  {
   this.savedState = state;
  }

  public string SavedState
  {
   get
   {
    return savedState;
   }
   set
   {
    savedState = value;
   }
  }
 }
}

public class Caretaker
{
 private MementoIF memento;
  
 public MementoIF retrieveMemento()
 {
  return this.memento;
 }

 public void savaMemento( MementoIF memento )
 {
  this.memento = memento;
 }

}

public class Client
{
 private static Originator o = new Originator();
 private static Caretaker c = new Caretaker();

 public static void main(string[] args)
 {
  o.State = "On";

  //保存
  c.savaMemento( o.createMemento() );

  o.State = "Off";

  //恢复
  o.restoreMemento( c.retrieveMemento() );
 }
}

5、要点

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