21_C#设计模式-备忘录模式

Design Patterns

备忘录模式

刘 伟 (Sunny)\rweiliu_china@126.com

大纲

\r

备忘录模式概述\r备忘录模式的结构与实现\r备忘录模式的应用实例\r实现多次撤销\r备忘录模式的优缺点与适用环境\r

备忘录模式概述

备忘录模式——软件中的“后悔药”——撤销(Undo)

备忘录模式概述

分析\r通过使用备忘录模式可以让系统恢复到某一特定的历史状态\r首先保存软件系统的历史状态,当用户需要取消错误操作并且返回到某个历史状态时,可以取出事先保存的历史状态来覆盖当前状态\r

备忘录模式概述

备忘录模式的定义\r\r\r\r\r\r对象行为型模式

备忘录模式概述

备忘录模式的定义\r别名为标记(Token)模式\r提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤\r当前在很多软件所提供的撤销(Undo)操作中就使用了备忘录模式

备忘录模式的结构与实现

备忘录模式的结构\r\r

备忘录模式的结构与实现

备忘录模式的结构\r备忘录模式包含以下3个角色:\rOriginator(原发器)\rMemento(备忘录)\rCaretaker(负责人)

备忘录模式的结构与实现

备忘录模式的实现\r典型的原发器类代码:

备忘录模式的结构与实现

备忘录模式的实现\r典型的备忘录类代码:

备忘录模式的结构与实现

备忘录模式的实现\r除了Originator类,不允许其他类来调用备忘录类Memento的构造函数与相关方法\r如果允许其他类调用SetState()等方法,将导致在备忘录中保存的历史状态发生改变,通过撤销操作所恢复的状态就不再是真实的历史状态,备忘录模式也就失去了本身的意义 ?\r理想的情况是只允许生成该备忘录的原发器访问备忘录的内部状态

备忘录模式的结构与实现

备忘录模式的实现\rC#语言实现:\r将Memento类与Originator类定义在同一个程序集(Assembly)中来实现封装,使用访问标识符internal来定义Memento类,即保证其在程序集内可见\r将备忘录类作为原发器类的内部类,使得只有原发器才可以访问备忘录中的数据,其他对象都无法使用备忘录中的数据

备忘录模式的结构与实现

备忘录模式的实现\r典型的负责人类代码:

备忘录模式的结构与实现

备忘录模式的实现\r客户端演示代码:

备忘录模式的应用实例

实例说明

备忘录模式的应用实例

实例类图

中国象棋棋子撤销功能结构图

备忘录模式的应用实例

实例代码\r(1) Chessman:象棋棋子类,充当原发器\r(2) ChessmanMemento:象棋棋子备忘录类,充当备忘录\r(3) MementoCaretaker:象棋棋子备忘录管理类,充当负责人\r(4) Program:客户端测试类

演示……

参考代码 (DesignPattern\MementoSample)

备忘录模式的应用实例

结果及分析\r通过创建备忘录对象可以将象棋棋子的历史状态信息记录下来,在“悔棋”时取出存储在备忘录中的历史状态信息,用历史状态来覆盖当前状态,从而实现状态的撤销\r\r\r\r

实现多次撤销

动机\r有时候用户需要撤销多步操作\r实现方案:在负责人类中定义一个集合来存储多个备忘录,每个备忘录负责保存一个历史状态,在撤销时可以对备忘录集合进行逆向遍历,回到一个指定的历史状态,还可以对备忘录集合进行正向遍历,实现重做(Redo)或恢复操作,即取消撤销,让对象状态得到恢复\r\r\r

实现多次撤销

结构\r\r\r\r\r

改进之后的中国象棋棋子撤销功能结构图

实现多次撤销

实现\r\r\r\r\r

实现多次撤销

实现\r\r\r\r\r

演示……

参考代码 (DesignPattern\MementoExtend)

备忘录模式的优缺点与适用环境

模式优点\r提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤\r实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动

备忘录模式的优缺点与适用环境

模式缺点\r资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免地需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源\r\r

备忘录模式的优缺点与适用环境

模式适用环境\r保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时能够恢复到先前的状态,实现撤销操作\r防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象\r

思考

能否使用原型模式来创建备忘录对象?如果可以,如何实现?

END

Thanks!