前一篇文章解锁时光机用到了备忘录模式,那么什么是备忘录模式?
备忘录模式是一种行为型设计模式,它的核心思想是在不暴露对象内部细节的情况下,捕获并保存一个对象的内部状态,以便在将来可以恢复到这个状态。
这个模式就像一个"时光机",能够让你在程序运行时记录下某个时刻的状态,并在需要时"穿越"回去。
核心角色
备忘录模式通常包含三个主要角色:
-
发起人(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 的逻辑完全不需要改动。
这就是为什么代码二的设计如此优雅和可扩展。它不关心"如何"改变,只关心"改变前"和"改变后"的状态是什么,并将这些状态作为备忘录保存起来。