定义

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

一个备忘录是一个对象,它存储另一个对象在某个瞬间的内部状态,后者被称为备忘录的原发器。

结构和说明

行为型模式-备忘录模式 - 图1

示例代码

  1. public class MementoDemo {
  2. /**
  3. * 备忘录的窄接口,没有任何方法定义
  4. */
  5. public static interface Memento {
  6. }
  7. /**
  8. * 原发器对象
  9. */
  10. public static class Originator {
  11. /**
  12. * 示意,表示原发器对象
  13. */
  14. private String state;
  15. /**
  16. * 创建保存原发器对象的状态的备忘录对象
  17. *
  18. * @return 创建好的备忘录对象
  19. */
  20. public Memento createMemento() {
  21. MementoImpl memento = new MementoImpl(state);
  22. return memento;
  23. }
  24. /**
  25. * 重新设置原发器对象的状态,让其回到备忘录对象记录的状态
  26. *
  27. * @param memento
  28. * 记录有原发器状态的备忘录对象
  29. */
  30. public void setMemento(Memento memento) {
  31. this.state = ((MementoImpl)memento).getState();
  32. }
  33. /**
  34. * 真正的备忘录对象,实现备忘录接口 实现成私有的内部类,不让外部访问
  35. */
  36. private static class MementoImpl implements Memento {
  37. /**
  38. * 示意,表示原发器对象
  39. */
  40. @Getter
  41. private String state;
  42. public MementoImpl(String state) {
  43. this.state = state;
  44. }
  45. }
  46. }
  47. /**
  48. * 负责保存备忘录的对象
  49. */
  50. public static class Caretaker {
  51. /**
  52. * 记录被保存的备忘录对象
  53. */
  54. private Memento memento;
  55. /**
  56. * 保存备忘录对象
  57. *
  58. * @param memento
  59. * 被保存的备忘录对象
  60. */
  61. public void saveMemento(Memento memento) {
  62. this.memento = memento;
  63. }
  64. /**
  65. * 获取被保存的备忘录对象
  66. *
  67. * @return 被保存的备忘录对象
  68. */
  69. public Memento retriveMemento() {
  70. return this.memento;
  71. }
  72. }
  73. }

讲解

管理者对象

在备忘录模式中,管理者对象主要是负责保存备忘录对象。这里有几点要讲一下。

  • 并不一定要特别做出一个管理者对象来。广义地说,调用原发器获取备忘录对象后,备忘录对象放在哪里,哪个对象就可以算是管理者对象。
  • 管理者对象并不是只能管理一个备忘录对象,一个管理者对象可以管理很多备忘录对象。虽然前面的示例中是保存一个备忘录对象,但别忘了那只是个示意,并不是只能实现成那样。
  • 狭义的管理者对象是只管理同一类的备忘录对象,但广义的管理者对象可以管理不同类型的备忘录对象的。
  • 管理者对象需要实现的基本功能主要是: 存入备忘录对象、保存备忘录对象和获取备忘录对象。如果从功能上看,就是一个缓存功能的实现,或者是一个简单的对象实例池的实现。
  • 管理者虽然能存取备忘录对象,但是不能访问备忘录对象内部的数据。

调用顺序

使用备忘录模式的时候,分成了两个阶段,第一阶段是创建备忘录对象的阶段,第二个阶段是使用备忘录对象来恢复原发器对象状态的阶段。它们的调用顺序是不一样的。

创建备忘录对象

行为型模式-备忘录模式 - 图2

使用备忘录对象来恢复原发器对象状态

行为型模式-备忘录模式 - 图3

优缺点

优点

  • 更好的封装性

备忘录模式通过备忘录对象,来封装原发器对象的内部状态,虽然这个对象保存在原发器外部,但是由于备忘录对象的窄接口并不提供任何方法。这样有效的保证了原发器对象内部状态的封装,不把原发器对象的内部实现细节暴露给外部。

  • 简化了原发器

备忘录模式中,备忘录对象被存放到原发器对象之外,让客户来管理他们的请求状态,从而让原发器对象得到简化。

  • 宽接口和窄接口

备忘录模式,通过引入了窄接口和宽接口,使得不同的地方,对备忘录对象的访问是不一样的。窄接口保证了只有原发器可以才访问备忘录对象的状态。

缺点

  • 可能会导致高开销

备忘录对象的基本功能就是,备忘录对象的存储与恢复,它的基本实现对象就是缓存备忘录对象。这样一来,如果需要缓存的数据量很大,或者需要频繁的创建备忘录对象,开销是很大的。

思考

本质

保存和恢复内部状态。

何时选用

  • 如果必须保存一个对象在某个时刻的全部或者部分状态,方便以后在需要的时候,可以把对象恢复到先前的状态,可以使用备忘录模式。使用备忘录对象来封装和保存需要保存的内部状态,然后把备忘录对象保存到管理这对象中,在需要的时候,再从管理者对象中获取备忘录对象,来恢复对象的状态。
  • 如果需要保存一个对象的内部状态,但是如果用接口来让其他对象直接得到这些需要保存的状态,将会暴露对象的实现细节并破坏对象的封装性,这时可以使用备忘录模式,把备忘录对象实现成原发器对象的内部类,而且还是私有的,从而保证只有原发器对象才能访问该备忘录对象。这样即保存了需要保存的状态,又不会暴露原发器对象的内部实现细节。

相关模式

  • 备忘录模式和组合模式

这两个模式可以组合使用。
命令模式实现中,在实现命令的撤销和重做的时候,就可以使用备忘录模式,在命令操作的时候记下命令操作前后的状态,然后在命令撤销和重做的时候,直接使用相应的备忘录对象来恢复状态就可以了。
在这种撤销的执行顺序和重做的执行顺序可控的情况下,备忘录对象还可以采用增量式记录的方式,有效减少缓存的数据量。

  • 备忘录模式和原型模式

在原发器对象创建备忘录对象的时候,如果原发器对象中全部或者大部分的状态都需要保存,一个简介的方式就是直接克隆一个原发器对象。也就是说,这个时候备忘录对象里面存放的是一个原发器对象的实例。