模式补全
这一节按 八面剖析以理解一个概念 / ljg-learn 的思路整理为 Markdown 版本:先定锚,再用八个方向切开概念,最后压缩成公式、例子、类图和检验题。
定锚
备忘录模式(行为型)的通行定义:在不破坏封装的前提下捕获对象内部状态,并在之后恢复。
常见误解:备忘录不是随便暴露对象所有字段;它强调状态快照与封装边界。
核心词素:Memento 是纪念物、备忘物。它保存过去某一刻的状态。
八刀
历史
它常见于编辑器撤销、游戏存档、表单草稿。GoF 用它表达快照和恢复机制。
辩证
反面是外部对象直接读写内部字段。更高理解是:过去可以被保存,但内部仍要保密。
现象
写文章时按下保存快照,之后改坏了可以回到之前版本。
语言
Memento 是纪念物、备忘物。它保存过去某一刻的状态。
形式
memento = originator.save(); originator.restore(memento)。当状态巨大或频繁变化时,快照成本会很高。
存在
它让系统拥有记忆,同时不牺牲对象的边界。
美感
它美在琥珀:某一刻的状态被封存,等待未来重新发光。
元反思
快照隐喻容易忽略增量存储。换成“版本控制”隐喻,会更关注差异、压缩和历史管理。
内观
我是过去的一小块封存状态。外界可以保管我,却不能拆开我。需要时,我带对象回到那一刻。
八刀共同指向的深层结构:备忘录模式不是为了“炫技”,而是在某个变化点上建立边界,让稳定部分继续稳定,让变化部分有自己的位置。
压缩
公式:备忘录 = 原发器 + 状态快照 + 管理者
一句话:备忘录让对象能保存和恢复状态,同时不把内部结构摊开给外界。
结构图:
Originator -> Memento
Caretaker stores Memento动机/意图
当对象需要支持撤销、恢复或历史版本时,外部管理者如果直接读取内部字段,会破坏封装。备忘录模式的意图是在不暴露内部结构的前提下捕获对象状态,并在未来把对象恢复到某个历史时刻。
结构/角色
Originator:原发器,拥有内部状态,负责创建和恢复备忘录。Memento:备忘录,保存原发器某一刻的状态,对外尽量保持不可见或只读。Caretaker:管理者,保存备忘录历史,但不解析其中内容。Client:客户端触发保存、撤销或恢复流程。
典型 UML
classDiagram class Originator { -state +save(): Memento +restore(memento: Memento): void } class Memento { -state +getState() } class Caretaker { -history: Memento[] +backup(): void +undo(): void } Originator ..> Memento Caretaker o-- Memento Caretaker --> Originator
使用场景
- 编辑器撤销、游戏存档、表单草稿、配置回滚。
- 需要保存历史状态,但不能暴露对象内部字段。
- 状态快照可以接受一定存储成本。
- 需要把状态保存职责和历史管理职责分开。
正例:TypeScript
class EditorMemento {
constructor(private readonly content: string) {}
getContent() {
return this.content
}
}
class Editor {
private content = ""
type(text: string) {
this.content += text
}
save() {
return new EditorMemento(this.content)
}
restore(memento: EditorMemento) {
this.content = memento.getContent()
}
}正例:UML 类图
classDiagram class Editor { -content: string +save(): EditorMemento +restore(memento): void } class EditorMemento { -content: string +getContent(): string } class History Editor ..> EditorMemento History o-- EditorMemento
反例:TypeScript
class History {
snapshots: any[] = []
save(editor: any) {
this.snapshots.push({ content: editor.content })
}
}反例:UML 类图
classDiagram class History class Editor { +content: string } History --> Editor : reads internals
案例
某系统提供了用户信息操作模块,用户可以修改自己的各项信息。为了使操作过程更加人性化,现使用备忘录模式对系统进行改进,使得用户在进行了错误操作之后可以恢复到操作之前的状态。
掌握检验
- 备忘录模式为什么强调不破坏封装?
- Originator、Memento、Caretaker 各自是什么?
- 大对象频繁保存快照时,可以怎样优化?