前一篇文章解锁时光机用到了备忘录模式,那么什么是备忘录模式?
备忘录模式是一种行为型设计模式,它的核心思想是在不暴露对象内部细节的情况下,捕获并保存一个对象的内部状态,以便在将来可以恢复到这个状态。
这个模式就像一个"时光机",能够让你在程序运行时记录下某个时刻的状态,并在需要时"穿越"回去。
核心角色
备忘录模式通常包含三个主要角色:
-
发起人(Originator) :
- 这是需要被保存状态的对象。
- 它负责创建一个备忘录(
Memento
),来保存自己的当前状态。 - 它也能够使用备忘录来恢复到之前的状态。
- 在我们的 React 例子中,
reducer
函数和其中的state
对象就是发起人。它能创建和恢复状态。
-
备忘录(Memento) :
- 这是用于存储发起人内部状态的快照对象。
- 它提供一个受限的接口,只允许发起人访问其内部状态。外部对象(比如
caretaker
)无法直接修改备忘录的内容,只能将其作为"黑盒子"传递。 - 在我们的 React 例子中,
past
和future
数组中的每一个present
值,就是一个备忘录。它是一个简单的数值,不需要复杂的对象来封装。
-
管理者(Caretaker) :
- 负责保存和管理备忘录。
- 它不知道备忘录内部的具体细节,只知道备忘录是从发起人那里来的,并能在需要时将它还给发起人。
- 它不能对备忘录的内容进行任何操作,只能存储和检索。
- 在我们的 React 例子中,
state
对象中的past
和future
数组就是管理者 。reducer
函数负责将备忘录(即状态值)放入或取出这些数组。
工作流程
- 保存状态 :发起人(
Originator
)在需要时,创建一个备忘录(Memento
),将自己的当前状态保存进去。然后将这个备忘录交给管理者(Caretaker
)。 - 恢复状态 :当需要恢复时,管理者(
Caretaker
)将之前保存的备忘录交给发起人(Originator
)。发起人通过备忘录中的信息,将自己的状态恢复到之前的样子。
备忘录模式与代码示例
现在,让我们把这些角色对应到代码中,一切就变得清晰了:
- 发起人(Originator) :
state
对象中的present
值。它代表了当前的核心状态。 - 备忘录(Memento) :
past
和future
数组中的每一个数值。每个数值都是一个"状态快照"。 - 管理者(Caretaker) :
state
对象中的past
和future
数组。它们负责存储这些状态快照。
具体实现流程:
-
Increment 操作:
Originator
(present
)的状态即将改变。Originator
告诉Caretaker
(past
数组),"我马上要变了,这是我现在的样子,你帮我存一下。"Caretaker
将当前的present
值[...past, present]
存入past
数组。
-
Undo 操作:
Caretaker
(past
数组)将最后一个备忘录(past.at(-1)
)交给Originator
。Originator
接收这个备忘录,并将其恢复为自己的状态(present: past.at(-1)
)。- 同时,
Originator
将当前状态作为新的备忘录,交给另一个Caretaker
(future
数组),以便重做。
为什么这种模式更优越?
备忘录模式的优点在于它实现了解耦 。管理者(past
/future
数组)和发起人(present
值)之间只需要知道如何存取备忘录,而不需要知道备忘录内部的具体结构或如何改变状态。这意味着你可以轻松地改变 increment
或 decrement
的逻辑,而 undo
和 redo
的逻辑完全不需要改动。
这就是为什么代码二的设计如此优雅和可扩展。它不关心"如何"改变,只关心"改变前"和"改变后"的状态是什么,并将这些状态作为备忘录保存起来。