《设计模式之禅》之备忘录模式

一、备忘录模式的定义

备忘录模式提供了一种弥补真实世界缺陷的方法,让”后悔药”在程序的世界中真实可行,其定义如下:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

通用类(三个角色)

Originator发起人角色

记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。

Memento备忘录角色

负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。

Caretaker备忘录管理员角色

对备忘录进行管理、保存和提供备忘录。

二、备忘录模式的应用

1.备忘录模式的使用场景

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

2.备忘录模式的注意事项

(1)备忘录的生命期

备忘录创建出来就要在”最近”的代码中使用,要主动管理它的生命周期,建立就要使用,不使用就要立刻删除其引用,等待垃圾回收器对它的回收处理。

(2)备忘录的性能

不要在频繁建立备份的场景中使用备忘录模式(比如一个for循环),
原因有二:
一是控制不了备忘录建立的对象数量;
二是大对象的建立是要消耗资源的,系统的性能需要考虑。
因此,如果出现这样的代码,设计师就应该好好想想怎么修改架构了。

三、备忘录模式的扩展

1.clone方式的备忘录

注意:使用clone方式的备忘录模式,可以使用在比较简单的场景或者比较单一的场景中,尽量不要与其他的对象产生严重的耦合关系。

2.多状态的备忘录模式

注意:如果要设计一个在运行期间决定备份状态的框架,则建议采用AOP框架来实现,避免采用动态代理无谓地增加程序逻辑复杂性。

3.多备份的备忘录

注意:内存溢出问题,该备份一旦产生就装入内存,没有任何销毁的意向,这是非常危险的。因此,在系统设计时,要严格限定备忘录的创建,建议增加Map的上限,否则系统很容易产生内存溢出情况。

4.封装得更好一些

在系统管理上,一个备份的数据是完全、绝对不能修改的,它保证数据的洁净,避免数据污染而使备份失去意义。在我们的设计领域中,也存在着同样的问题,备份是不能随便篡改的,也就是说需要缩小备份出的备忘录的阅读权限,保证只能是发起人可读就成了。

四、最佳实践

备忘录模式是我们设计上”月光宝盒”,可以让我们回到需要的年代;是程序数据的”后悔药”,吃了它就可以返回上一个状态;是设计人员的定心丸,确保即使在最坏的情况下也能获得最近的对象状态。如果大家看懂了的话,请各位在设计的时候就不要使用数据库的临时表作为缓存备份数据了,虽然是一个简单办法,但是它加大了数据库操作的频繁度,把压力下放到数据库了,最好的解决办法就是使用备忘录模式。
代码例子:
https://github.com/developers-youcong/DesignPatternPractice/tree/master/Memento

文章目录
  1. 一、备忘录模式的定义
    1. 通用类(三个角色)
      1. Originator发起人角色
      2. Memento备忘录角色
      3. Caretaker备忘录管理员角色
  2. 二、备忘录模式的应用
    1. 1.备忘录模式的使用场景
    2. 2.备忘录模式的注意事项
      1. (1)备忘录的生命期
      2. (2)备忘录的性能
  3. 三、备忘录模式的扩展
    1. 1.clone方式的备忘录
    2. 2.多状态的备忘录模式
    3. 3.多备份的备忘录
    4. 4.封装得更好一些
  4. 四、最佳实践