备忘录模式(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
- 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
前言:为什么需要备忘录模式?
在软件开发中,我们经常需要保存对象的某个状态,并在后续需要时恢复它。例如,游戏中的“存档”功能、文档编辑器的“撤销/重做”操作,或者数据库事务的回滚机制。然而,直接保存对象状态可能带来复杂性,比如如何避免暴露内部细节,如何管理多个版本的状态,以及如何高效地恢复数据。
备忘录模式(Memento Pattern)正是为了解决这类问题而诞生的设计模式。它通过一种“封装”的方式,将对象的内部状态保存到一个独立的对象中,从而实现状态的灵活保存与恢复。本文将从基础概念、工作原理、实际案例到代码实现,逐步解析这一模式的精髓。
备忘录模式的核心概念
1. 模式定义与角色划分
备忘录模式属于行为型模式,其核心是通过一个“备忘录”对象来捕获并保存另一个对象(发起人)的内部状态,同时允许在需要时恢复该状态。
模式涉及三个关键角色:
-
发起人(Originator):
- 负责创建备忘录对象,并将自身状态保存到备忘录中。
- 同时,发起人可以利用备忘录对象恢复之前的状态。
-
备忘录(Memento):
- 存储发起人的内部状态。
- 对外仅暴露必要的接口,以保护发起人的敏感数据不被直接修改。
-
管理者(Caretaker):
- 负责保管备忘录对象,并根据需要传递备忘录给发起人。
- 管理者通常不关心备忘录的具体内容,仅负责存储和管理。
2. 模式的核心思想
备忘录模式的核心是封装状态转移。通过将状态保存在独立的备忘录对象中,发起人可以专注于自身业务逻辑,而管理者则专注于状态的存储与传递。这种设计避免了直接暴露对象的内部细节,同时确保了状态管理的灵活性和安全性。
备忘录模式的工作原理详解
1. 状态保存与恢复的流程
备忘录模式的工作流程可以分为以下步骤:
- 创建备忘录:发起人调用方法生成一个备忘录对象,将当前状态数据封装到该对象中。
- 传递备忘录:发起人将备忘录对象传递给管理者,由管理者负责存储或管理。
- 恢复状态:当需要恢复历史状态时,管理者将备忘录对象返还给发起人,发起人通过该对象恢复自身状态。
2. 一个形象的比喻:游戏存档系统
假设我们开发一款游戏,玩家需要随时保存进度并能在后续加载。此时,备忘录模式可以这样应用:
- 发起人(Originator):游戏引擎,负责管理玩家当前的关卡、血量、金币等状态。
- 备忘录(Memento):保存玩家当前所有状态的“存档文件”。
- 管理者(Caretaker):游戏的存档管理器,负责存储多个存档文件,并在玩家选择时提供对应的存档。
通过这种方式,游戏引擎无需关心存档如何存储,存档管理器也无需了解存档的具体内容,两者通过备忘录对象协作,实现了状态的灵活管理。
实现备忘录模式的步骤与代码示例
1. 步骤解析
- 定义发起人(Originator):创建一个类,包含需要保存的内部状态,并提供方法生成备忘录对象。
- 定义备忘录(Memento):创建一个类,用于封装发起人的状态数据。该类应限制对外暴露的接口,仅允许发起人访问敏感数据。
- 定义管理者(Caretaker):创建一个类,负责存储和管理备忘录对象。
2. Java语言的代码示例
以下是一个简单的文档编辑器案例,演示如何使用备忘录模式实现“撤销”功能:
发起人(Originator)
public class Document {
private String content; // 文档内容
private int version; // 版本号
// 生成备忘录
public Memento saveToMemento() {
return new Memento(content, version);
}
// 恢复备忘录
public void restoreFromMemento(Memento memento) {
this.content = memento.getContent();
this.version = memento.getVersion();
}
// 其他业务方法...
}
备忘录(Memento)
public class Memento {
private final String content;
private final int version;
private Memento(String content, int version) {
this.content = content;
this.version = version;
}
// 仅暴露必要信息给发起人
String getContent() { return content; }
int getVersion() { return version; }
// 禁止外部直接创建备忘录
public static class MementoBuilder {
public Memento createMemento(String content, int version) {
return new Memento(content, version);
}
}
}
管理者(Caretaker)
public class HistoryManager {
private List<Memento> mementos = new ArrayList<>();
public void save(Memento memento) {
mementos.add(memento);
}
public Memento undo() {
if (!mementos.isEmpty()) {
return mementos.remove(mementos.size() - 1);
}
return null;
}
}
使用示例
public class Main {
public static void main(String[] args) {
Document doc = new Document();
HistoryManager history = new HistoryManager();
// 初始状态
doc.setContent("Hello World!");
history.save(doc.saveToMemento());
// 修改内容
doc.editContent("Hello, this is a new version.");
// 撤销到上一版本
Memento lastVersion = history.undo();
doc.restoreFromMemento(lastVersion);
System.out.println("Current content: " + doc.getContent());
}
}
备忘录模式的典型应用场景
1. 游戏中的存档系统
玩家可以在任何时间点保存游戏进度(如角色位置、装备、任务进度),并在后续加载这些存档。
2. 文档编辑器的撤销/重做功能
用户编辑文档时,系统自动保存每个操作前后的状态,支持回退到任意历史版本。
3. 数据库事务的回滚机制
在事务执行过程中,系统可能需要记录中间状态,以便在发生错误时回滚到安全点。
4. 配置管理
保存软件的配置状态,方便用户在误操作后快速恢复到之前的配置。
备忘录模式的优势与局限性
优势
- 解耦状态管理:发起人无需关心状态如何保存,管理者无需了解状态细节,两者通过备忘录协作。
- 安全性:备忘录对象对外隐藏了发起人的敏感数据,仅允许发起人访问。
- 灵活性:可以保存多个备忘录,支持多级撤销或恢复。
局限性
- 内存占用:保存大量备忘录可能导致内存消耗过高,需权衡存储数量与性能。
- 序列化问题:若状态数据复杂(如包含对象引用),需确保备忘录对象能正确序列化与反序列化。
- 适用场景有限:仅适用于需要频繁保存和恢复状态的场景,对于简单状态管理可能过度设计。
与其他模式的对比:备忘录 vs 命令模式
备忘录模式与命令模式(Command Pattern)都涉及状态的保存与操作,但核心目标不同:
| 对比项 | 备忘录模式 | 命令模式 |
|------------------|-----------------------------------|---------------------------------|
| 核心目标 | 保存对象状态,支持恢复 | 封装操作为对象,支持撤销/重做 |
| 状态存储 | 通过备忘录对象存储原始数据 | 通过命令对象存储操作指令 |
| 触发恢复 | 主动调用恢复方法 | 通过执行撤销或重做操作 |
例如,在文档编辑器中:
- 备忘录模式直接保存文档内容和版本号,支持直接回退到某个状态。
- 命令模式则记录每次编辑操作(如“插入文本”“删除段落”),通过反向执行命令实现撤销。
两种模式可结合使用:例如,备忘录保存状态快照,而命令记录具体操作,从而实现更细粒度的撤销功能。
总结与实践建议
备忘录模式通过分离状态保存与业务逻辑,为复杂系统的状态管理提供了优雅的解决方案。对于开发者而言,掌握这一模式能显著提升代码的可维护性和扩展性。
关键实践建议:
- 明确需求:仅在需要频繁保存或恢复状态时使用,避免过度设计。
- 保护敏感数据:确保备忘录对象仅暴露必要接口,防止数据泄露。
- 管理内存:根据场景限制备忘录的数量,或采用策略(如仅保存最近N个版本)。
通过本文的讲解与案例,希望读者能够理解备忘录模式的原理,并在实际开发中灵活应用这一模式,解决状态管理的痛点。
(全文约 1800 字)