本文目录导读:

我来详细讲解Java中的备忘录模式(Memento Pattern),这是一种用于保存和恢复对象状态的行为型设计模式。
备忘录模式的定义
备忘录模式允许在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在将来某个时刻可以将该对象恢复到之前保存的状态。
核心角色
- Originator(发起人):需要保存状态的对象
- Memento(备忘录):存储发起人内部状态的对象
- Caretaker(管理者):负责保存和管理备忘录对象
实现方式
基本实现(内部类方式)
// 发起人 - 需要保存状态的对象
class Originator {
private String state;
public void setState(String state) {
System.out.println("设置状态为: " + state);
this.state = state;
}
public String getState() {
return state;
}
// 创建备忘录
public Memento saveStateToMemento() {
return new Memento(state);
}
// 从备忘录恢复状态
public void getStateFromMemento(Memento memento) {
state = memento.getState();
}
// 备忘录类 - 作为内部类实现,保证封装性
public static class Memento {
private final String state;
private Memento(String state) {
this.state = state;
}
private String getState() {
return state;
}
}
}
// 管理者 - 负责保存备忘录
class Caretaker {
private List<Originator.Memento> mementoList = new ArrayList<>();
public void add(Originator.Memento state) {
mementoList.add(state);
}
public Originator.Memento get(int index) {
return mementoList.get(index);
}
}
// 测试代码
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
// 保存状态
originator.setState("状态 #1");
caretaker.add(originator.saveStateToMemento());
originator.setState("状态 #2");
caretaker.add(originator.saveStateToMemento());
originator.setState("状态 #3");
// 恢复到状态 #1
originator.getStateFromMemento(caretaker.get(0));
System.out.println("恢复后的状态: " + originator.getState());
}
}
支持多状态保存的版本
import java.util.HashMap;
import java.util.Map;
// 更复杂的发起人
class ComplexOriginator {
private String name;
private int health;
private int mana;
private int level;
private Map<String, Integer> inventory;
public ComplexOriginator(String name) {
this.name = name;
this.health = 100;
this.mana = 50;
this.level = 1;
this.inventory = new HashMap<>();
}
public void attack(int damage) {
health -= damage;
}
public void addItem(String item, int quantity) {
inventory.put(item, inventory.getOrDefault(item, 0) + quantity);
}
public Memento save() {
return new Memento(name, health, mana, level, new HashMap<>(inventory));
}
public void restore(Memento memento) {
this.name = memento.getName();
this.health = memento.getHealth();
this.mana = memento.getMana();
this.level = memento.getLevel();
this.inventory = new HashMap<>(memento.getInventory());
}
@Override
public String toString() {
return String.format("角色: %s, 生命: %d, 魔法: %d, 等级: %d, 背包: %s",
name, health, mana, level, inventory);
}
// 备忘录类
public static class Memento {
private final String name;
private final int health;
private final int mana;
private final int level;
private final Map<String, Integer> inventory;
private Memento(String name, int health, int mana, int level,
Map<String, Integer> inventory) {
this.name = name;
this.health = health;
this.mana = mana;
this.level = level;
this.inventory = inventory;
}
// 只提供getter方法,不提供setter
public String getName() { return name; }
public int getHealth() { return health; }
public int getMana() { return mana; }
public int getLevel() { return level; }
public Map<String, Integer> getInventory() { return inventory; }
}
}
// 管理者
class GameCaretaker {
private Stack<ComplexOriginator.Memento> undoStack = new Stack<>();
private Stack<ComplexOriginator.Memento> redoStack = new Stack<>();
public void saveState(ComplexOriginator.Memento memento) {
undoStack.push(memento);
redoStack.clear(); // 新操作后清除重做栈
}
public ComplexOriginator.Memento undo() {
if (!undoStack.isEmpty()) {
ComplexOriginator.Memento memento = undoStack.pop();
redoStack.push(memento);
return undoStack.isEmpty() ? null : undoStack.peek();
}
return null;
}
public ComplexOriginator.Memento redo() {
if (!redoStack.isEmpty()) {
ComplexOriginator.Memento memento = redoStack.pop();
undoStack.push(memento);
return memento;
}
return null;
}
public boolean canUndo() {
return !undoStack.isEmpty();
}
public boolean canRedo() {
return !redoStack.isEmpty();
}
}
// 测试
public class GameSaveDemo {
public static void main(String[] args) {
ComplexOriginator player = new ComplexOriginator("勇士");
GameCaretaker caretaker = new GameCaretaker();
System.out.println("初始状态: " + player);
// 游戏进行中
player.attack(30);
player.addItem("生命药水", 2);
caretaker.saveState(player.save());
System.out.println("保存点1: " + player);
// 继续游戏
player.attack(50);
player.level = 3;
player.addItem("魔法水晶", 1);
caretaker.saveState(player.save());
System.out.println("保存点2: " + player);
// 撤销到保存点1
ComplexOriginator.Memento undoState = caretaker.undo();
if (undoState != null) {
player.restore(undoState);
System.out.println("撤销后: " + player);
}
// 重做
ComplexOriginator.Memento redoState = caretaker.redo();
if (redoState != null) {
player.restore(redoState);
System.out.println("重做后: " + player);
}
}
}
使用序列化的通用实现
import java.io.*;
// 使用Java序列化实现通用备忘录
class SerializableMemento<T extends Serializable> {
private byte[] stateData;
public void saveState(T originator) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(originator);
stateData = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public T restoreState() {
try (ByteArrayInputStream bis = new ByteArrayInputStream(stateData);
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
// 需要保存状态的对象实现Serializable
class GameCharacter implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int health;
private int mana;
private transient String tempData; // 不保存的临时数据
public GameCharacter(String name) {
this.name = name;
this.health = 100;
this.mana = 50;
this.tempData = "临时数据";
}
// getters and setters...
@Override
public String toString() {
return String.format("GameCharacter{name='%s', health=%d, mana=%d}",
name, health, mana);
}
}
实际应用场景
文本编辑器的撤销/重做功能
import java.util.Stack;
class TextEditor {
private StringBuilder content;
private Stack<String> history;
public TextEditor() {
this.content = new StringBuilder();
this.history = new Stack<>();
}
public void write(String text) {
history.push(content.toString()); // 保存当前状态
content.append(text);
}
public void undo() {
if (!history.isEmpty()) {
content = new StringBuilder(history.pop());
}
}
public String getContent() {
return content.toString();
}
}
数据库事务管理
class DatabaseTransaction {
private Map<String, Object> originalState;
private Map<String, Object> currentState;
public DatabaseTransaction(Map<String, Object> initialState) {
this.originalState = new HashMap<>(initialState);
this.currentState = new HashMap<>(initialState);
}
public Memento createMemento() {
return new Memento(new HashMap<>(currentState));
}
public void restoreMemento(Memento memento) {
this.currentState = new HashMap<>(memento.getState());
}
public static class Memento {
private final Map<String, Object> state;
private Memento(Map<String, Object> state) {
this.state = state;
}
private Map<String, Object> getState() {
return state;
}
}
}
优缺点分析
优点:
- 保持了封装边界:备忘录对象只对发起人可见
- 简化了发起人:不需要管理版本历史
- 支持撤销操作:方便实现撤销/重做功能
- 状态管理灵活:可以保存多个检查点
缺点:
- 资源消耗大:如果保存的状态很大,会占用大量内存
- 实现复杂度高:需要处理深拷贝和浅拷贝问题
- 可能带来性能问题:频繁保存和恢复状态会影响性能
最佳实践建议
- 使用深拷贝:确保备忘录中的状态是独立的副本
- 限制备忘录大小:设置最大保存数量或使用LRU算法
- 使用压缩:对于大量数据,考虑压缩存储
- 合理使用原型模式:通过克隆创建备忘录副本
- 考虑使用序列化:对于复杂对象,序列化可以简化实现
与其他模式的关系
- 命令模式:备忘录模式常用于实现命令模式的撤销功能
- 原型模式:备忘录可以使用原型模式创建对象副本
- 迭代器模式:可以用来遍历历史状态
备忘录模式是实现状态保存和恢复的强大工具,特别适合需要撤销/重做功能、保存检查点或实现事务回滚的场景。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播