备忘录模式(Memento Pattern)是一种行为型设计模式,通过捕获对象的内部状态,并在不破坏封装的情况下保存这个状态,以便稍后恢复到先前的状态。这种模式常用于实现撤销/重做功能、状态快照和历史记录管理。
设计模式原理
备忘录模式的核心是通过备忘录对象封装发起人的内部状态,保管人负责存储和传递备忘录,而不直接访问状态,从而保护封装性。
结构
- 发起人(Originator):创建备忘录,保存当前状态到备忘录中,并从备忘录恢复状态。
- 备忘录(Memento):存储发起人的内部状态,提供狭窄接口给保管人,宽接口给发起人。
- 保管人(Caretaker):负责保存备忘录,但不检查或修改其内容。
优点
- 封装性强:保管人无法访问或修改备忘录内部状态,保护发起人隐私。
- 简单实现:易于添加保存/恢复功能,无需暴露内部细节。
- 支持历史管理:可维护状态栈,实现撤销/重做。
- 灵活扩展:备忘录可序列化,支持持久化存储。
缺点
- 内存消耗:大量备忘录可能占用过多内存。
- 复杂状态:深层嵌套对象需深拷贝,避免引用问题。
- 性能影响:频繁保存/恢复可能导致开销。
- 版本兼容:状态变化时,旧备忘录可能失效。
适用场景
- 撤销/重做:如文本编辑器、图形工具。
- 状态快照:如游戏存档、AI对话历史。
- 历史回放:如日志系统、调试工具。
- 智能代理:如AI记忆管理,支持回滚决策。
TypeScript 实现示例
我们实现一个AI智能体记忆系统,智能体通过备忘录保存对话历史和状态,支持回滚和恢复。代码使用TypeScript确保类型安全。
项目结构
go
ai-memory/
├── src/
│ ├── memento.ts // 核心接口
│ ├── agent.ts // 发起人
│ ├── memoryManager.ts // 保管人
│ ├── main.ts // 执行示例
├── tsconfig.json
├── package.json
1. 安装依赖
bash
npm init -y
npm install typescript @types/node
npx tsc --init
配置 tsconfig.json
:
json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"moduleResolution": "node"
}
}
2. 定义接口 (memento.ts)
typescript
export interface Memento {
getState(): any;
setState(state: any): void;
}
export interface Originator {
createMemento(): Memento;
restore(memento: Memento): void;
getState(): any;
setState(state: any): void;
}
export interface Caretaker {
saveMemento(memento: Memento): void;
restoreMemento(): Memento | null;
undo(): Memento | null;
}
3. 实现发起人 (agent.ts)
typescript
import { Memento, Originator } from './memento';
interface AIMemoryState {
conversation: string[];
decisions: string[];
timestamp: number;
}
export class AIAgent implements Originator {
private state: AIMemoryState;
constructor(initialState: AIMemoryState) {
this.state = initialState;
}
createMemento(): Memento {
return new MemoryMemento({ ...this.state });
}
restore(memento: Memento): void {
this.state = memento.getState();
console.log('AI代理状态已恢复');
}
getState(): AIMemoryState {
return { ...this.state };
}
setState(newState: Partial<AIMemoryState>): void {
this.state = { ...this.state, ...newState };
}
// AI行动:添加对话和决策
addConversation(message: string): void {
this.state.conversation.push(message);
console.log(`对话添加:${message}`);
}
makeDecision(decision: string): void {
this.state.decisions.push(decision);
this.state.timestamp = Date.now();
console.log(`决策添加:${decision}`);
}
}
class MemoryMemento implements Memento {
private state: AIMemoryState;
constructor(state: AIMemoryState) {
this.state = { ...state };
}
getState(): AIMemoryState {
return { ...this.state };
}
setState(state: AIMemoryState): void {
this.state = { ...state };
}
}
4. 实现保管人 (memoryManager.ts)
typescript
import { Memento, Caretaker } from './memento';
export class MemoryManager implements Caretaker {
private mementos: Memento[] = [];
saveMemento(memento: Memento): void {
this.mementos.push(memento);
console.log('备忘录已保存');
}
restoreMemento(): Memento | null {
if (this.mementos.length === 0) {
console.log('无备忘录可恢复');
return null;
}
const memento = this.mementos.pop()!;
console.log('备忘录已恢复');
return memento;
}
undo(): Memento | null {
if (this.mementos.length < 2) {
console.log('无法回滚');
return null;
}
const previous = this.mementos.pop()!;
console.log('状态已回滚');
return previous;
}
getHistorySize(): number {
return this.mementos.length;
}
}
5. 运行示例 (main.ts)
typescript
import { AIAgent } from './agent';
import { MemoryManager } from './memoryManager';
const initialState = {
conversation: ['系统启动'],
decisions: [],
timestamp: Date.now()
};
const agent = new AIAgent(initialState);
const manager = new MemoryManager();
// 初始保存
manager.saveMemento(agent.createMemento());
// 第一步行动
agent.addConversation('用户:你好');
agent.makeDecision('问候用户');
manager.saveMemento(agent.createMemento());
// 第二步行动
agent.addConversation('用户:今天天气如何?');
agent.makeDecision('查询天气');
manager.saveMemento(agent.createMemento());
// 模拟错误,回滚
console.log('当前状态:', agent.getState());
const previousMemento = manager.undo();
if (previousMemento) {
agent.restore(previousMemento);
console.log('回滚后状态:', agent.getState());
}
// 恢复最后状态
const lastMemento = manager.restoreMemento();
if (lastMemento) {
agent.restore(lastMemento);
console.log('恢复后状态:', agent.getState());
}
console.log(`历史记录大小:${manager.getHistorySize()}`);
6. 编译与运行
bash
npx tsc
node dist/main.js
运行后,控制台输出类似:
css
备忘录已保存
对话添加:用户:你好
决策添加:问候用户
备忘录已保存
对话添加:用户:今天天气如何?
决策添加:查询天气
备忘录已保存
当前状态: { conversation: [ '系统启动', '用户:你好', '用户:今天天气如何?' ], decisions: [ '问候用户', '查询天气' ], timestamp: 1695090000000 }
状态已回滚
AI代理状态已恢复
回滚后状态: { conversation: [ '系统启动', '用户:你好' ], decisions: [ '问候用户' ], timestamp: 1695090000000 }
备忘录已恢复
AI代理状态已恢复
恢复后状态: { conversation: [ '系统启动', '用户:你好', '用户:今天天气如何?' ], decisions: [ '问候用户', '查询天气' ], timestamp: 1695090000000 }
历史记录大小:1
总结
备忘录模式的优点在于其封装性强、简单实现、支持历史管理和灵活扩展。发起人状态通过备忘录封装,保管人无法直接访问,确保隐私保护;易于添加保存/恢复功能,无需暴露内部细节;可维护状态栈,实现撤销/重做;备忘录可序列化,支持持久化存储。该模式特别适用于撤销/重做、状态快照、历史回放和智能代理场景,如文本编辑器、游戏存档、日志系统,以及AI对话历史管理,支持回滚决策避免错误累积。