当前位置: 首页 > news >正文

设计模式——备忘录设计模式(行为型)

摘要

备忘录设计模式是一种行为型设计模式,用于在不破坏封装性的前提下,捕获对象的内部状态并在需要时恢复。它包含三个关键角色:原发器(Originator)、备忘录(Memento)和负责人(Caretaker)。该模式的优点包括保留对象状态、支持回滚和易于实现撤销/重做功能,但缺点是状态快照可能占用大量内存且管理复杂。其结构可通过嵌套类或中间接口类图表示,实现方式涉及原发器创建和恢复备忘录、备忘录存储状态、负责人保存和获取备忘录。适合用于需要撤销/重做功能或频繁保存状态的场景,但当状态变化不频繁或内存受限时则不适合。实战示例包括数据库脚本、实体类和状态保存与撤销API。此外,该模式可与其他设计模式或技术结合使用,如状态机模式、命令模式、责任链模式、原型模式、观察者模式、策略模式、持久化机制和Spring AOP/注解。

1. 备忘录设计模式定义

备忘录设计模式(Memento Pattern) 是一种行为型设计模式,用于在不破坏封装性的前提下,捕获一个对象的内部状态,并在以后需要时将其恢复到原先的状态。

1.1. ✅ 关键角色

角色

说明

Originator

原发器,拥有内部状态,需要保存快照并恢复自身状态

Memento

备忘录,存储 Originator的内部状态,通常是一个不可变对象

Caretaker

负责人,管理备忘录的保存与恢复,但不访问其内容

1.2. 优点:

  • 保留对象状态,支持回滚
  • 不破坏封装(状态通过 Memento 管理)
  • 易于实现撤销/重做功能

1.3. 缺点:

  • 状态快照可能占用大量内存
  • Caretaker 可能需要管理多个 Memento,带来管理复杂性

2. 备忘录设计模式结构

2.1. 基于嵌套类类图

2.2. 基于中间接口类图

2.3. 备忘录时序图

3. 备忘录设计模式实现方式

备忘录设计模式(Memento Pattern)实现方式的核心在于:在不破坏对象封装性的前提下,捕获并保存对象的内部状态,以便之后可以将其恢复。

3.1. 🧩 Originator(原发器):拥有状态,负责创建和恢复备忘录

public class Originator {private String state; // 需要保存的内部状态public void setState(String state) {this.state = state;System.out.println("设置状态为:" + state);}public String getState() {return state;}// 创建备忘录public Memento saveStateToMemento() {return new Memento(state);}// 从备忘录恢复状态public void restoreStateFromMemento(Memento memento) {this.state = memento.getState();System.out.println("恢复状态为:" + state);}
}

3.2. 🧩 Memento(备忘录):只暴露给 Originator,用于存储状态

public class Memento {private final String state;public Memento(String state) {this.state = state;}// 只有 Originator 使用protected String getState() {return state;}
}

3.3. 🧩 Caretaker(管理者):负责保存、获取备忘录,但不操作内容

import java.util.ArrayList;
import java.util.List;public class Caretaker {private List<Memento> mementoList = new ArrayList<>();// 添加备忘录public void add(Memento memento) {mementoList.add(memento);}// 获取某个备忘录public Memento get(int index) {return mementoList.get(index);}
}

3.4. 🚀 使用示例(模拟状态保存与恢复)

public class Client {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("状态 #1");originator.setState("状态 #2");caretaker.add(originator.saveStateToMemento()); // 保存状态2originator.setState("状态 #3");caretaker.add(originator.saveStateToMemento()); // 保存状态3originator.setState("状态 #4");// 恢复状态originator.restoreStateFromMemento(caretaker.get(0)); // 恢复到状态2originator.restoreStateFromMemento(caretaker.get(1)); // 恢复到状态3}
}

3.5. ✅ 备忘录总结

组件

职责

Originator

负责创建和恢复备忘录

Memento

存储状态(不可变对象)

Caretaker

管理多个备忘录(可以是栈、队列、列表)

3.6. ✅ 延伸使用(如 Spring 项目中)

你可以将备忘录模式与:

  • Spring 注解(如 @Service@Component
  • 数据持久化(备忘录入库,支持长期存档)
  • REST 接口撤销(如风控规则撤销)
  • 状态机结合(状态保存+回滚)

4. 备忘录设计模式适合场景

4.1. ✅ 适合使用备忘录模式的场景

场景

说明

撤销操作(Undo/Redo)功能

比如文本编辑器、IDE、画图工具,用户希望能够一步步撤销操作。

状态快照与回滚

比如事务性系统、工作流、审批流、游戏存档等,可以保存当前状态,失败时快速回滚。

风控策略、配置管理

在金融风控系统中,策略配置改动后,能够恢复到某个时间点前的策略状态。

状态机状态保存

和状态机结合使用,记录每个状态变化的历史,可实现状态追溯。

临时修改但可还原的场景

比如购物车中的临时优惠应用、试算试验。

AI / 数据建模模拟

在做一系列模拟实验时,需要保存中间状态,方便比较或回退。

4.2. ❌ 不适合使用备忘录模式的场景

场景

原因

状态对象非常庞大或频繁变动

会频繁创建大量备份,造成内存/存储负担。例如大型图像、视频编辑。

备份数据无法或不允许暴露给外部

即使模式保证封装性,有些敏感状态如密钥/隐私也不应被存储。

状态之间无明显断点或快照意义不大

比如高频实时流系统,数据快速变化,快照意义小。

备份状态对业务无价值

若状态回滚从不发生,记录也无实际意义,反而增加维护成本。

替代机制更适合

比如用数据库的事务机制或版本控制系统就能解决的,不必使用设计模式实现复杂备份。

总结:备忘录模式适用于“状态可保存且可能需要还原”的对象,在撤销、版本控制、配置管理等场景特别合适。

5. 备忘录设计模式实战示例

在风控系统中,用户可配置规则,每次变更都自动保存历史状态,并支持「撤销」功能。

5.1. ✳️ 数据库脚本(rule_history.sql

CREATE TABLE rule_config (id BIGINT PRIMARY KEY AUTO_INCREMENT,rule_code VARCHAR(64),rule_content TEXT,version INT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);CREATE TABLE rule_memento (id BIGINT PRIMARY KEY AUTO_INCREMENT,rule_id BIGINT,rule_content TEXT,version INT,saved_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

5.2. ✳️ 实体类

@Data
@Entity
@Table(name = "rule_config")
public class RuleConfig {@Id@GeneratedValueprivate Long id;private String ruleCode;private String ruleContent;private Integer version;
}
@Data
@Entity
@Table(name = "rule_memento")
public class RuleMemento {@Id@GeneratedValueprivate Long id;private Long ruleId;private String ruleContent;private Integer version;private Timestamp savedAt;
}

5.3. 🧠 备忘录模式结构

5.3.1. 备忘录(Memento)

public class RuleMementoSnapshot {private final String content;private final Integer version;public RuleMementoSnapshot(String content, Integer version) {this.content = content;this.version = version;}public String getContent() {return content;}public Integer getVersion() {return version;}
}

5.3.2. 发起人(Originator)

@Component
public class RuleOriginator {public RuleMementoSnapshot save(RuleConfig ruleConfig) {return new RuleMementoSnapshot(ruleConfig.getRuleContent(), ruleConfig.getVersion());}public void restore(RuleConfig ruleConfig, RuleMementoSnapshot snapshot) {ruleConfig.setRuleContent(snapshot.getContent());ruleConfig.setVersion(snapshot.getVersion());}
}

5.3.3. 负责人(Caretaker)

@Service
public class RuleHistoryService {@Autowiredprivate RuleMementoRepository mementoRepository;public void saveMemento(Long ruleId, RuleMementoSnapshot snapshot) {RuleMemento memento = new RuleMemento();memento.setRuleId(ruleId);memento.setRuleContent(snapshot.getContent());memento.setVersion(snapshot.getVersion());mementoRepository.save(memento);}public RuleMementoSnapshot getLastMemento(Long ruleId) {RuleMemento latest = mementoRepository.findTopByRuleIdOrderBySavedAtDesc(ruleId);return new RuleMementoSnapshot(latest.getRuleContent(), latest.getVersion());}
}

5.4. 💡 状态保存与撤销 API(Controller)

@RestController
@RequestMapping("/api/rule")
public class RuleController {@Autowired private RuleRepository ruleRepository;@Autowired private RuleHistoryService historyService;@Autowired private RuleOriginator originator;@PostMapping("/update")public ResponseEntity<String> updateRule(@RequestBody RuleConfig newRule) {RuleConfig old = ruleRepository.findById(newRule.getId()).orElseThrow();RuleMementoSnapshot snapshot = originator.save(old);historyService.saveMemento(old.getId(), snapshot);old.setRuleContent(newRule.getRuleContent());old.setVersion(old.getVersion() + 1);ruleRepository.save(old);return ResponseEntity.ok("规则已更新并记录历史");}@PostMapping("/undo/{ruleId}")public ResponseEntity<String> undo(@PathVariable Long ruleId) {RuleConfig rule = ruleRepository.findById(ruleId).orElseThrow();RuleMementoSnapshot lastSnapshot = historyService.getLastMemento(ruleId);originator.restore(rule, lastSnapshot);ruleRepository.save(rule);return ResponseEntity.ok("回滚成功");}
}

6. 备忘录设计模式思考

备忘录设计模式(Memento Pattern)在实际开发中往往不会单独使用,而是与其他设计模式组合,以解决更复杂的状态管理、回滚、撤销等需求。下面是常见的组合方式和典型应用场景,尤其适合 金融风控、流程引擎、配置管理 等场景。

6.1. ✅ 备忘录模式 + 状态机模式(State Pattern)

组合说明:

  • 状态机负责管理状态切换逻辑;
  • 备忘录负责保存每个状态快照,实现状态回滚/撤销

场景示例:

  • 风控审批流程中,支持将任务状态退回上一步。
  • 订单状态(待支付 → 已支付 → 配送中)中用户申请退款,需要回退到「待支付」。

6.2. ✅ 备忘录模式 + 命令模式(Command Pattern)

组合说明:

  • 命令封装用户操作;
  • 备忘录记录执行前的状态,实现 undo() 操作。

场景示例:

  • 金融交易撤销;
  • 系统管理员修改风控规则,每次操作都可以回滚。

6.3. ✅ 备忘录模式 + 责任链模式(Chain of Responsibility)

组合说明:

  • 每个处理节点执行任务前记录状态;
  • 执行失败时利用备忘录回滚上一步处理。

场景示例:

  • 信贷审批流程,每个环节出错需恢复上一次状态。

6.4. ✅ 备忘录模式 + 原型模式(Prototype Pattern)

组合说明:

  • 使用原型的浅/深拷贝方式快速创建备忘录对象;
  • 提高状态快照的创建效率。

场景示例:

  • 在风险规则配置页面修改参数时,使用深克隆构建快照并保存。

6.5. ✅ 备忘录模式 + 观察者模式(Observer Pattern)

组合说明:

  • 状态变化时通知观察者;
  • 备忘录用于记录状态变化历史。

场景示例:

  • 配置变更通知下游服务,但允许撤销恢复上一个配置。

6.6. ✅ 备忘录模式 + 策略模式(Strategy Pattern)

组合说明:

  • 策略负责计算/处理;
  • 备忘录记录策略执行前后的状态,便于结果回退。

场景示例:

  • 多种风控策略组合决策后,若发现误判,恢复上一次执行前的状态。

6.7. ✅ 备忘录模式 + 持久化机制(如 Repository、数据库)

组合说明:

  • 备忘录对象不是只存在于内存,而是持久化保存(如 JSON 存库)。
  • 支持跨进程或长时间状态恢复。

场景示例:

  • 某条风控规则上线后的历史版本备份,可通过后台 UI 操作恢复。

6.8. ✅ 备忘录模式 + Spring AOP/注解

组合说明:

  • 使用注解(如 @MementoBackup)自动拦截方法;
  • 在方法前后生成并记录状态快照,实现零侵入式回滚机制

场景示例:

  • Spring Boot 应用中,支持风控参数调整回滚功能,只需加注解即可。

6.9. 🧩 组合参考表

组合模式

典型作用

适用系统类型

状态机

管理状态转换+回滚

审批系统、风控流程引擎

命令

操作封装+撤销

配置平台、策略决策平台

责任链

多环节状态保护

风控引擎、流程引擎

原型

快速复制状态

配置回滚、草稿管理

观察者

状态广播+恢复

分布式配置中心

策略

策略组合+状态对比

风控策略、限额控制

持久化

状态历史存档

长期任务跟踪系统

AOP/注解

自动化拦截/回滚

企业级 Spring 应用

博文参考

相关文章:

  • Linux中的System V通信标准-共享内存、消息队列以及信号量
  • react与vue的渲染原理
  • 【C++】类的构造函数
  • 自定义序列生成器之单体架构实现
  • window 显示驱动开发-驱动程序处理的Multiple-Processor优化
  • 使用 So-VITS-SVC 实现明星声音克隆与视频音轨替换实战全流程
  • Kotlin 中 companion object 扩展函数详解
  • ShenNiusModularity项目源码学习(33:ShenNius.Admin.Mvc项目分析-18)
  • 力扣HOT100之动态规划:32. 最长有效括号
  • leetcode90.子集II:排序与同层去重的回溯优化策略
  • Java后端优化:对象池模式解决高频ObjectMapper实例化问题及性能影响
  • 玩客云 OEC/OECT 笔记(2) 运行RKNN程序
  • 华为云Flexus+DeepSeek征文|利用华为云 Flexus 云服务一键部署 Dify 平台开发文本转语音助手全流程实践
  • py爬虫的话,selenium是不是能完全取代requests?
  • 【Day43】
  • 链式前向星图解
  • 06.MySQL数据库操作详解
  • Elasticsearch 读写流程深度解析
  • 相机--相机标定
  • mac安装brew时macos无法信任ruby的解决方法
  • 如何做平台网站/站外引流推广渠道
  • wordpress仿天涯主题/杭州seo搜索引擎优化
  • 企业网站开发论文/优化品牌seo关键词
  • wordpress 快速发布/福州搜索引擎优化公司
  • 微信小程序开发介绍/seo搜索引擎优化
  • 目前最流行网站开发软件/关键字优化