williambirkin

恭喜发财!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

意图
在不破坏封装性的前提条件下,捕获一个对象的内部状态,然后在该对象之外保存这个状态。以后在需要的时候可以将该对象恢复到原先保存的状态。

结构


1.Memento(备忘录):保存Originator(原发器)对象的内部状态,Originator根据需要决定保存哪些内部状态,防止自身以外的其它对象访问备忘录。备忘录实际上是由两个接口,其中Caretaker(管理者)只能看到备忘录的窄接口,即它只能将备忘录传递给其他对象;而原发器可以看到一个宽接口,允许他访问回到原先状态所需的所有数据,理想的情况是只允许生成原发器访问本备忘录的内部状态。
2.Originator:创建一个备忘录以记录当前时刻内部状态,使用备忘录恢复内部状态。
3.Caretaker:负责保存备忘录,但不能处理其中的内容。

使用场合
需要保存对象在某一时刻的状态,并在以后需要的时候恢复到这个状态。同时又不希望暴露对象的视线细节,破坏对象的封装性,这时需要使用备忘录模式。

效果
备忘录模式在不破坏封装性的前提下,实现对对象内部状态的外部保存。但如果保存的状态过多,或者设计不合理,则将产生过多的备忘录对象而占用大量的系统资源。


备忘录模式的基本框架
备忘录模式的难点在于在确保封装的前提下,将内部状态放到外部保存。如果单纯从保存状态出发(即宽接口方式),备忘录并不难实现。

宽接口实现备忘录模式

下面是Originator的代码框架:

using System;
using System.Collections.Generic;
using System.Text;

namespace MemoPattern.ex28_3
{
    
class Originator
    
{
        
private State state;

        
public Originator()
        
{
            state
=new State();
            state.Level 
= 1;
            state.StateName 
= "Bejin";
        }


        
public string StateName
        
{
            
get return state.StateName; }
            
set { state.StateName = value; }
        }


        
public int Level
        
{
            
get return state.Level; }
            
set { state.Level = value; }
        }


        
public Memo CreateMemo()
        
{
            
return new Memo(this.state);
        }


        
public void SetState(Memo m)
        
{
            
this.state=m.State;
        }

    }

}

State是保存状态的类:

using System;
using System.Collections.Generic;
using System.Text;

namespace MemoPattern.ex28_3
{
    
class State:ICloneable
    
{
        
public string StateName="";
        
public int Level=-1;

        
ICloneable メンバ
    }

}

Memonto类如下:
在保存状态时需要注意传值与传地址的区别。要保存的是新的状态对象而非原状态对象的引用。

可以使用原型模式,使State有Clone功能:
state=st.clone();

using System;
using System.Collections.Generic;
using System.Text;

namespace MemoPattern.ex28_3
{
    
class Memo
    
{
        
private State _state;

        
public Memo(State state)
        
{
            _state 
= (State)state.Clone();
        }


        
public State State
        
{
            
get return _state; }
            
set { _state = value; }
        }

    }

}

Caretaker代码如下: 
使用强类型集合存储备忘录。

using System;
using System.Collections.Generic;
using System.Text;

namespace MemoPattern.ex28_3
{
    
class Caretaker:List<Memo>
    
{
        
public Memo Restore()
        
{
            
if(Count==0)return null;

            Memo m 
= this[Count - 1];

            RemoveAt(Count
-1);
            
return m;
        }

    }

}

执行代码如下:

        static void Main()
        
{
            ex28_3.Originator o
=new MemoPattern.ex28_3.Originator();
            ex28_3.Caretaker c 
= new MemoPattern.ex28_3.Caretaker();
            c.Add(o.CreateMemo());

            o.StateName 
= "one";
            o.Level 
= 100;

            c.Add(o.CreateMemo());

            o.StateName 
= "two";
            o.Level 
= 200;

            c.Add(o.CreateMemo());

            ex28_3.Memo m 
= c.Restore();

            
while (m != null)
            
{
                o.SetState(m);
                Console.WriteLine(o.StateName);
                m 
= c.Restore();
            }

        }

这种方式状态State对外是透明的,因此状态都可以被修改。这并不符合备忘录模式的要求。下面将采用接口屏蔽的方式完善以上代码。

接口屏蔽实现备忘录模式

首先定义一个接口,其目的是屏蔽Memonto中的细节。

using System;
using System.Collections.Generic;
using System.Text;

namespace MemoPattern.ex28_4
{
    
public class IMemo
    
{

    }

}

改造Originator
我们将Memonto作为Originator的私有类,这一步非常重要。

using System;
using System.Collections.Generic;
using System.Text;

namespace MemoPattern.ex28_4
{
    
class Originator
    
{
        
private State state;

        
public Originator()
        
{
            state
=new State();
            state.Level 
= 1;
            state.StateName 
= "Bejin";
        }


        
public string StateName
        
{
            
get return state.StateName; }
            
set { state.StateName = value; }
        }


        
public int Level
        
{
            
get return state.Level; }
            
set { state.Level = value; }
        }


        
public IMemo CreateMemo()
        
{
            
return new Memo(this.state);
        }


        
public void SetState(IMemo m)
        
{
            
this.state = ((Memo)m).State;
        }


        
private class Memo:IMemo
        
{
            
private State _state;

            
public Memo(State st)
            
{
                _state 
= (State)st.Clone();
            }


            
public State State
            
{
                
get return _state; }
                
set { _state = value; }
            }

        }

    }

}

 改造Caretaker

using System;
using System.Collections.Generic;
using System.Text;

namespace MemoPattern.ex28_4
{
    
class Caretaker:List<IMemo>
    
{
        
public IMemo Restore()
        
{
            
if(Count==0)return null;

            IMemo m 
= this[Count - 1];

            RemoveAt(Count
-1);
            
return m;
        }

    }

}


实现代码:

        static void Main()
        
{
            ex28_4.Originator o 
= new MemoPattern.ex28_4.Originator();
            ex28_4.Caretaker c 
= new MemoPattern.ex28_4.Caretaker();
            c.Add(o.CreateMemo());

            o.StateName 
= "one";
            o.Level 
= 100;

            c.Add(o.CreateMemo());

            o.StateName 
= "two";
            o.Level 
= 200;

            c.Add(o.CreateMemo());

            ex28_4.IMemo m 
= c.Restore();

            
while (m != null)
            
{
                o.SetState(m);
                Console.WriteLine(o.StateName);
                m 
= c.Restore();
            }


        }


相关模式
1.命令模式:别忘录可以作为撤销操作维护状态。
2.迭代器: 备忘录可以用于迭代器,为期提供迭代状态。
posted on 2007-02-08 10:01  williambirkin  阅读(434)  评论(0编辑  收藏  举报