设计模式-备忘录模式

备忘录模式(Memento Pattern)是一种行为型设计模式,允许在不破坏封装的前提下,捕获一个对象的内部状态,并在未来需要时将其恢复。备忘录模式在需要保存和恢复对象状态的场景下非常实用,比如撤销操作、历史记录功能等。


备忘录模式的角色组成:

  1. 发起人(Originator)
    • 负责创建备忘录对象并保存自己的状态,同时可以使用备忘录恢复其状态。
  2. 备忘录(Memento)
    • 用于存储发起人的内部状态,通常是一个简单的数据类。
  3. 管理者(Caretaker)
    • 负责存储和管理备忘录,不能直接操作备忘录的内容,只能通过发起人恢复状态。

示例代码:文本编辑器的撤销功能

问题背景

假设有一个简单的文本编辑器,支持输入文本和撤销操作。为了实现撤销功能,需要保存每次输入的状态,并在用户撤销时恢复之前的状态。


实现代码

// 备忘录类:存储状态
class Memento {
    private final String state; // 文本内容

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

// 发起人类:文本编辑器
class TextEditor {
    private String content = ""; // 当前文本内容

    // 创建备忘录
    public Memento save() {
        return new Memento(content);
    }

    // 恢复备忘录
    public void restore(Memento memento) {
        this.content = memento.getState();
    }

    // 添加文本
    public void append(String text) {
        content += text;
    }

    // 获取当前内容
    public String getContent() {
        return content;
    }
}

// 管理者类:负责管理备忘录
class Caretaker {
    private final List<Memento> history = new ArrayList<>(); // 保存备忘录的历史记录
    private int currentIndex = -1; // 当前备忘录的索引

    // 添加备忘录
    public void save(Memento memento) {
        // 如果在中途操作,清除后续历史
        while (currentIndex < history.size() - 1) {
            history.remove(history.size() - 1);
        }
        history.add(memento);
        currentIndex++;
    }

    // 撤销操作
    public Memento undo() {
        if (currentIndex <= 0) {
            System.out.println("无法撤销!");
            return null;
        }
        currentIndex--;
        return history.get(currentIndex);
    }

    // 恢复操作
    public Memento redo() {
        if (currentIndex >= history.size() - 1) {
            System.out.println("无法恢复!");
            return null;
        }
        currentIndex++;
        return history.get(currentIndex);
    }
}

// 客户端
public class MementoPatternExample {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        Caretaker caretaker = new Caretaker();

        // 第一次编辑
        editor.append("Hello");
        caretaker.save(editor.save()); // 保存状态
        System.out.println("当前内容: " + editor.getContent());

        // 第二次编辑
        editor.append(", World!");
        caretaker.save(editor.save()); // 保存状态
        System.out.println("当前内容: " + editor.getContent());

        // 撤销
        editor.restore(caretaker.undo());
        System.out.println("撤销后内容: " + editor.getContent());

        // 再次撤销
        editor.restore(caretaker.undo());
        System.out.println("再次撤销后内容: " + editor.getContent());

        // 恢复
        editor.restore(caretaker.redo());
        System.out.println("恢复后内容: " + editor.getContent());
    }
}

输出结果:

当前内容: Hello
当前内容: Hello, World!
撤销后内容: Hello
再次撤销后内容: 
恢复后内容: Hello

备忘录模式的优点:

  1. 封装性良好
    • 备忘录对外隐藏了发起人的内部状态,只能通过发起人进行状态的保存和恢复。
  2. 简化撤销和恢复功能
    • 非常适合需要撤销和恢复功能的场景,管理复杂状态变更变得简单。
  3. 遵循单一职责原则
    • 备忘录只负责存储状态,发起人负责逻辑处理,管理者负责保存和恢复。

备忘录模式的缺点:

  1. 内存消耗较大
    • 如果状态信息较多,保存多个备忘录可能会占用大量内存。
  2. 实现复杂度较高
    • 在某些场景下,管理备忘录的逻辑可能变得复杂。

备忘录模式的适用场景:

  1. 需要保存对象状态以支持撤销/恢复功能
  2. 对象的内部状态需要完全封装,避免被其他代码直接访问。
  3. 需要在某些操作失败后,恢复到之前的状态

备忘录模式广泛应用于编辑器、游戏存档、事务回滚等场景。

posted @ 2025-01-14 08:59  庞某人  阅读(21)  评论(0)    收藏  举报