Java备忘录模式保存恢复对象状态

wen java案例 2

本文目录导读:

Java备忘录模式保存恢复对象状态

  1. 备忘录模式的定义
  2. 核心角色
  3. 实现方式
  4. 实际应用场景
  5. 优缺点分析
  6. 最佳实践建议
  7. 与其他模式的关系

我来详细讲解Java中的备忘录模式(Memento Pattern),这是一种用于保存和恢复对象状态的行为型设计模式。

备忘录模式的定义

备忘录模式允许在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在将来某个时刻可以将该对象恢复到之前保存的状态。

核心角色

  1. Originator(发起人):需要保存状态的对象
  2. Memento(备忘录):存储发起人内部状态的对象
  3. 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;
        }
    }
}

优缺点分析

优点:

  1. 保持了封装边界:备忘录对象只对发起人可见
  2. 简化了发起人:不需要管理版本历史
  3. 支持撤销操作:方便实现撤销/重做功能
  4. 状态管理灵活:可以保存多个检查点

缺点:

  1. 资源消耗大:如果保存的状态很大,会占用大量内存
  2. 实现复杂度高:需要处理深拷贝和浅拷贝问题
  3. 可能带来性能问题:频繁保存和恢复状态会影响性能

最佳实践建议

  1. 使用深拷贝:确保备忘录中的状态是独立的副本
  2. 限制备忘录大小:设置最大保存数量或使用LRU算法
  3. 使用压缩:对于大量数据,考虑压缩存储
  4. 合理使用原型模式:通过克隆创建备忘录副本
  5. 考虑使用序列化:对于复杂对象,序列化可以简化实现

与其他模式的关系

  • 命令模式:备忘录模式常用于实现命令模式的撤销功能
  • 原型模式:备忘录可以使用原型模式创建对象副本
  • 迭代器模式:可以用来遍历历史状态

备忘录模式是实现状态保存和恢复的强大工具,特别适合需要撤销/重做功能、保存检查点或实现事务回滚的场景。

抱歉,评论功能暂时关闭!