备忘录(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
个人理解:其实备忘录很容易理解,就是将当下的状态放到一个容器中,保存起来,当需要这个状态的时候,直接从容器中拿出这个状态重新赋给对象就好了。
首先看Originator这个类,这个类里边封装了一个State的属性,还有两个方法,首先说CreateMemento,这个方法的作用就是实例化一个Memento的对象,并且把状态(state)传进去,这就需要Memento里边有一个构造函数来接收originator传入的状态。而第二个SetMomento的方法,就是恢复状态时用的,将Memento实例化出来的对象的状态重新赋给这个类的状态。在说Caretaker这个类,他其实说白了就是Memento的一个实体类,负责存放备忘录的信息。
客户端如何调用呢?请看下边的代码
static void Main(string[] args) { Originator o=new Originator(); //实例化发起人类 o.State="on"; //开始状态为on o.Show(); Caretaker c=new Caretaker(); //实例化备忘录实体 c.Memento=o.CreateMemento(); //发起人类实例化备忘录对象,并通过构造函数,将状态保存在这个对象中 o.State="off"; //这是状态发生改变 o.Show(); o.SetMemento(c.Memento);//调用发起人的恢复状态的额方法,参数是备忘录的对象,因为开始的状态保存在这个对象中 o.Show(); Console.Read(); }
我们从客户端中可以发现,我们具体在备忘录中存放了哪些属性,在客户端是看不见的,这就体现了这个模式的一个良好的封装性,因为所有的属性都是封装到发起人(Originator)这个类中的,而我们有时又需要将一些属性保存到外部对象中,这就需要发起人这个类自身有读取的方法,这样才可以保证内部信息对外部来说是封闭的。
但其实在机房合作的过程中,封闭性做不到那么好,因为UI界面就相当于我们的客户端,就拿BasicData窗体举例,开始窗体从数据库获取到基础数据,并且显示到界面上,这就说明我们起始的状态就是通过界面获取的,UI层就相当于我们的发起人。所以说我们不能完全套用这个模式,但是作为练手也无妨。代码如下(修改学生信息窗体):有不合适的地方,希望大师们多多指点:
发起人类(Info)
class Info { #region 需要保存的属性 private string _department; private string _explain; private string _grade; private string _major; private string _sex; private string _Strclass; private string _studentName; private string _studentNo; public string Department { get { return _department; } set { _department = value; } } public string Explain { get { return _explain; } set { _explain = value; } } public string Grade { get { return _grade; } set { _grade = value; } } public string Major { get { return _major; } set { _major = value; } } public string Sex { get { return _sex; } set { _sex = value; } } public string Strclass { get { return _Strclass; } set { _Strclass = value; } } public string StudentName { get { return _studentName; } set { _studentName = value; } } public string StudentNo { get { return _studentNo; } set { _studentNo = value; } } #endregion public void GetInitState(StudentEntity studentinfo) //获得学生最开始的值,这个值UI界面传入的学生实体获得 { this.Department = studentinfo.department; this.StudentName = studentinfo.studentName; this.StudentNo = studentinfo.studentNo; this.Sex = studentinfo.sex; this.Strclass = studentinfo.Strclass; this.Major = studentinfo.major; this.Explain = studentinfo.explain; this.Grade = studentinfo.grade; } public InfoStateMemento SaveState()//实例化备忘录,并且存入最初状态 { return (new InfoStateMemento(StudentNo, StudentName, Sex, Department, Strclass, Grade, Explain ,Major)); } public void RecoveryState(InfoStateMemento memento) //恢复状态 { this.StudentNo = memento.StudentNo; this.StudentName = memento.StudentName; this.Sex = memento.Sex; this.Department = memento.Department; this.Strclass = memento.Strclass; this.Grade = memento.Grade; this.Explain = memento.Explain; this.Major = memento.Major; } }
备忘录类
public InfoStateMemento(string studentNo, string studentName, string sex, string department, string strclass, string grade, string explain,string major) { this.studentNo = studentNo; this.studentName = studentName; this.sex = sex; this.department = department; this.strclass = strclass; this.grade = grade; this.explain = explain; this.major = major; } //因为此类不能对存入的属性进行修改,所以这里只有只读器 public string Department { get { return department; } } public string Explain { get { return explain; } } public string Grade { get { return grade; } } public string Major { get { return major; } } public string Sex { get { return sex; } } public string Strclass { get { return strclass; } } public string StudentName { get { return studentName; } } public string StudentNo { get { return studentNo; } } }
class InfoStateCaretaker { private InfoStateMemento memento; public InfoStateMemento Memento //Memento属性 { get { return memento; } set { memento = value; } } }
客户端调用
首先要实例化发起人和备忘录实体类(这两个要写在方法外),因为多次进行实例化的话,里边存的初始数据就没有了
Info studentDan = new Info(); InfoStateCaretaker stateAdmin = new InfoStateCaretaker();
private void Cancel_Click(object sender, EventArgs e) { studentDan.RecoveryState(stateAdmin.Memento);//从状态中得到数据 txtStudentNo.Text = studentDan.StudentNo; txtDepartment.Text = studentDan.Department; txtExplain.Text = studentDan.Explain; txtMajor.Text = studentDan.Major; txtStudentName.Text = studentDan.StudentName; txtClass.Text = studentDan.Strclass; cboSex.Text = studentDan.Sex; txtGrade.Text = studentDan.Grade; }
其实在机房中这个功能不用备忘录模式非常好实现,只要界面加载出来,将学生信息保存在学生实体中,当点击取消按钮,直接将实体中的值重新赋给窗体就行了,绕了这么大一圈就是想要了解了解备忘录模式的应用,我们在使用设计模式的时候,大多有一个感受,代码量增多,而且好处也没怎么体会到,这也许是我们用的地方不是那么的合适,或者说我们没有在继续的开发这个系统,当我们需要扩展出来一个功能的时候,就能体会到设计模式易于扩展的好处了,先学习先了解,不用考虑那么多就好了