本文目录导读:

Java备忘录模式详解
备忘录模式(Memento Pattern)用于在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便将来恢复。
核心角色
- 发起人(Originator):需要保存状态的对象
- 备忘录(Memento):存储发起人内部状态
- 管理者(Caretaker):负责保存和管理备忘录
经典案例:游戏存档系统
// 1. 备忘录类 - 存储游戏状态
class GameMemento {
private int level;
private int health;
private String position;
private int score;
public GameMemento(int level, int health, String position, int score) {
this.level = level;
this.health = health;
this.position = position;
this.score = score;
}
// 只提供getter方法,不提供setter(保持不可变性)
public int getLevel() { return level; }
public int getHealth() { return health; }
public String getPosition() { return position; }
public int getScore() { return score; }
}
// 2. 发起人类 - 游戏角色
class GameCharacter implements Cloneable {
private int level;
private int health;
private String position;
private int score;
public GameCharacter() {
this.level = 1;
this.health = 100;
this.position = "起点";
this.score = 0;
}
// 创建备忘录(保存状态)
public GameMemento save() {
return new GameMemento(level, health, position, score);
}
// 从备忘录恢复状态
public void restore(GameMemento memento) {
if (memento == null) {
throw new IllegalArgumentException("备忘录不能为空");
}
this.level = memento.getLevel();
this.health = memento.getHealth();
this.position = memento.getPosition();
this.score = memento.getScore();
}
// 游戏操作
public void fight(int damage) {
this.health -= damage;
System.out.println("战斗受伤,当前生命值: " + health);
}
public void moveTo(String newPosition, int scoreGain) {
this.position = newPosition;
this.score += scoreGain;
System.out.println("移动到: " + position + ", 得分: " + score);
}
public void levelUp() {
this.level++;
this.health = 100;
System.out.println("升级到等级: " + level + ", 生命恢复满");
}
@Override
public String toString() {
return String.format("等级:%d, 生命:%d, 位置:%s, 分数:%d",
level, health, position, score);
}
}
// 3. 管理者类 - 存档管理器
class GameSaveManager {
private Stack<GameMemento> saveSlots = new Stack<>();
private int maxSlots;
public GameSaveManager(int maxSlots) {
this.maxSlots = maxSlots;
}
// 存档(压入栈中)
public void saveGame(GameCharacter character) {
if (saveSlots.size() >= maxSlots) {
System.out.println("存档已满,覆盖最早的存档");
saveSlots.remove(0);
}
saveSlots.push(character.save());
System.out.println("游戏已保存,当前存档数: " + saveSlots.size());
}
// 读档(从栈顶取出)
public void loadGame(GameCharacter character) {
if (saveSlots.isEmpty()) {
System.out.println("没有可用的存档");
return;
}
GameMemento memento = saveSlots.pop();
character.restore(memento);
System.out.println("游戏已加载");
}
// 查看所有存档
public void listSaves() {
System.out.println("当前存档数量: " + saveSlots.size());
// 注意:这里无法查看备忘录的具体内容,因为备忘录是私有的
}
}
// 4. 客户端代码
public class MementoPatternDemo {
public static void main(String[] args) {
GameCharacter player = new GameCharacter();
GameSaveManager saveManager = new GameSaveManager(3);
System.out.println("初始状态:");
System.out.println(player);
// 第一次存档
saveManager.saveGame(player);
// 游戏进行
player.moveTo("森林", 50);
player.fight(30);
System.out.println("战斗后: " + player);
// 第二次存档
saveManager.saveGame(player);
// 继续游戏
player.levelUp();
player.moveTo("城堡", 100);
player.fight(40);
System.out.println("继续游戏后: " + player);
// 读档(回到第二次存档)
System.out.println("\n读档操作:");
saveManager.loadGame(player);
System.out.println("读档后: " + player);
// 再读档(回到第一次存档)
System.out.println("\n再次读档:");
saveManager.loadGame(player);
System.out.println("读档后: " + player);
}
}
输出示例
初始状态:
等级:1, 生命:100, 位置:起点, 分数:0
游戏已保存,当前存档数: 1
移动到: 森林, 得分: 50
战斗受伤,当前生命值: 70
战斗后: 等级:1, 生命:70, 位置:森林, 分数:50
游戏已保存,当前存档数: 2
升级到等级: 2, 生命恢复满
移动到: 城堡, 得分: 150
战斗受伤,当前生命值: 60
继续游戏后: 等级:2, 生命:60, 位置:城堡, 分数:150
读档操作:
游戏已加载
读档后: 等级:1, 生命:70, 位置:森林, 分数:50
再次读档:
游戏已加载
读档后: 等级:1, 生命:100, 位置:起点, 分数:0
实际应用场景
文本编辑器撤销功能
class TextEditor {
private StringBuilder content;
private Stack<EditorMemento> history;
public void write(String text) {
history.push(save());
content.append(text);
}
public void undo() {
if (!history.isEmpty()) {
restore(history.pop());
}
}
}
数据库事务回滚
class DatabaseTransaction {
private Map<String, Object> state;
private List<TransactionMemento> savepoints;
public void begin() {
savepoints.clear();
savepoints.add(save()); // 保存初始状态
}
public void rollback() {
if (!savepoints.isEmpty()) {
restore(savepoints.get(0));
}
}
}
注意事项
优点
- 状态还原:可以轻松实现撤销/重做功能
- 封装性:备忘录对象不暴露内部状态给外部
- 简化发起人:发起人不需管理历史状态
缺点
- 资源消耗:如果状态很大,频繁保存会消耗内存
- 实现复杂度:需要额外的备忘录和管理者类
- 语言限制:Java中需要额外处理Object的克隆
最佳实践
- 使用浅拷贝/深拷贝:确保状态对象的完整复制
- 管理内存:限制存档数量或使用压缩存储
- 序列化支持:对于复杂的对象,考虑使用序列化
与其他模式结合
- 命令模式:用于实现更复杂的撤销/重做
- 原型模式:通过克隆简化状态保存
备忘录模式非常适合需要提供撤销功能的应用,如文本编辑器、游戏存档、绘图软件等场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播