备忘录模式:把对象状态安全地存档
撤销、草稿箱、游戏存档、流程回退,都需要把对象某一刻的状态保存下来,之后还能恢复。备忘录模式把这件事做成一个独立职责。
一、痛点:状态散落在对象内部,外部不知道如何恢复
一个文档编辑器支持“保存草稿”和“撤销”。最简单做法是把title、content、version三个字段逐个暴露出去:
Stringtitle=editor.getTitle();Stringcontent=editor.getContent();intversion=editor.getVersion();// 恢复时再逐个 set 回去这会让编辑器的内部结构暴露给调用方,而且每次状态字段变化,保存和恢复逻辑都要跟着改。
备忘录模式的回答:让原发器自己生成一个不可变的快照对象,外部只负责保存和归还,不知道快照内部长什么样。
二、实现:原发器 → 备忘录 → 负责人
第一步:定义备忘录
publicrecordDocumentMemento(Stringtitle,Stringcontent,intversion){}备忘录不可变,只作为状态的载体。
第二步:原发器负责创建和恢复快照
publicclassDocumentEditor{privateStringtitle;privateStringcontent;privateintversion;publicDocumentEditor(Stringtitle,Stringcontent){this.title=title;this.content=content;this.version=1;}publicvoidmodify(Stringtitle,Stringcontent){this.title=title;this.content=content;this.version++;}publicDocumentMementosave(){returnnewDocumentMemento(title,content,version);}publicvoidrestore(DocumentMementomemento){this.title=memento.title();this.content=memento.content();this.version=memento.version();}publicStringsnapshot(){return"title="+title+", content="+content+", version="+version;}}第三步:负责人保存历史
importjava.util.ArrayDeque;importjava.util.Deque;publicclassEditorHistory{privatefinalDeque<DocumentMemento>history=newArrayDeque<>();publicvoidpush(DocumentMementomemento){history.push(memento);}publicDocumentMementopop(){returnhistory.pop();}}第四步:客户端执行保存与撤销
DocumentEditoreditor=newDocumentEditor("标题","初稿");EditorHistoryhistory=newEditorHistory();history.push(editor.save());editor.modify("标题 V2","第二版");history.push(editor.save());editor.modify("标题 V3","第三版");editor.restore(history.pop());System.out.println(editor.snapshot());// V2editor.restore(history.pop());System.out.println(editor.snapshot());// 初稿三、备忘录的边界控制
备忘录模式的关键在于“只有原发器知道快照内容”。工程上有两种常见做法:
| 方式 | 做法 | 优点 |
|---|---|---|
| 窄接口 | 负责人只看到不透明对象 | 状态细节封装得最彻底 |
| 宽接口 | 备忘录暴露状态,负责人可直接读写 | 灵活,但封装性较弱 |
上面示例使用record暴露了状态,适合状态简单、类内部可控的场景。如果状态复杂且需要严格封装,可以设计成只有原发器能访问内部字段的私有类。
四、工程化提醒
- 注意内存:大对象快照如果保存太多,会造成内存压力,需设置历史条数上限;
- 深拷贝问题:备忘录中若包含可变对象,保存时同样要处理深拷贝;
- 与命令模式配合:命令模式负责“做什么”,备忘录模式负责“状态怎么回退”,两者常一起实现撤销/重做。
小结
备忘录模式一句话:让对象自己保存自己的过去。它把快照的创建与恢复收口到原发器内部,外部只负责“存起来”和“拿回来”,既支持回退,也保护了对象状态封装。