设计模式——备忘录模式

108 阅读3分钟

一.定义

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

二.类图

2.1 常规备忘录

image.png

  • Originator发起人角色,记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。
  • Memento备忘录角色,负责存储Originator发起人对象的内部状态,在恢复的时候提供数据。
  • Caretaker备忘录管理员角色:对备忘录进行管理 保存和提供备忘录

2.2 clone方式的备忘录

image.png     使用Clone方式的备忘录后,不符合定义中“在该对象之外保存这个状态”这句话,这个方式适用于比较简单的场景或者比较单一的场景中,尽量不要与其他对象产生严重的耦合关系。

2.3 多状态下备忘录模式

image.png

  • BeanUtils类其中backupProp是把发起人的所有属性值转换到HashMap中,方便备忘录角色存储;restoreProp方法则是把HashMap中的值返回到发起人角色中。不使用Originator对象的拷贝而使用HashMap的原因是为了保证发起人的通用性,在多恢复动作的时候需要对该对象进行多次赋值操作,也容易产生错误。

2.4 强安全性备忘录模式

image.png

  • 在系统管理上,一个备份的数据是完全、绝对不能修改的,它保证数据的洁净,避免数据污染而使备份失去意义。
  • 设计领域中,把备忘录的阅读权限保证只能是发起人可读就成了,使用内置类可以做到这一点。
  • IMemento是一个空接口。
  • 没有绝对的安全,可以使用refelect反射修改Memento的数据

三.使用场景

  • 需要保存和恢复数据的相关状态场景。
  • 提供一个可回滚的操作;比如Word中CTRL+Z组合键等
  • 需要监控的副本场景中。例如要监控一个对象的属性,但是监控又不应该作为系统的主业务来调用,它只是边缘应用,既是出现监控不准,错误报警也影响不大,因此一般的做法是备份一个主线程中的对象,然后由分析程序类分析。
  • 数据库连接的事务管理就是用的备忘录模式。

四.注意事项

  • 备忘录的生命期。备忘录创建出来就要在“最近“的代码中使用,要主动管理它的生命周期,建立就要使用,不使用就要立刻删除其引用,等待垃圾回收器对它的回收处理。
  • 备忘录性能。不要在频繁尽力备份的场景中使用备忘录模式,比如一个for循环中,一是因为控制不了备忘录建立的对象数量,而是大对象建立是要消耗资源的,会影响系统的性能。
  • 如果要设计一个在运行期决定备份状态的框架,则建议采用AOP框架来实现,避免采用动态代理无谓地增加程序的逻辑性。