小易说IT 小易说IT

Java备忘录模式 (Memento) 示例代码

备忘录模式:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,后续可以把对象恢复到原先保存的状态。 角色:

  1. Originator(发起人):需要保存状态的对象,可以创建备忘录,也可以恢复状态

  2. Memento(备忘录):存储发起人的内部状态,只允许发起人访问

  3. Caretaker(管理者):负责保存备忘录,不对备忘录内容操作

/**
 * 备忘录 Memento:保存发起人状态,私有构造,仅Originator可访问
 */
class Memento {
    // 保存的状态
    private final String state;

    // 构造方法私有化,只有同包Originator能创建
    Memento(String state) {
        this.state = state;
    }

    String getState() {
        return state;
    }
}

/**
 * Originator 发起人:文本编辑器,可以保存快照、恢复快照
 */
class Editor {
    private String content;

    public void setContent(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    // 创建备忘录(保存当前状态)
    public Memento saveToMemento() {
        return new Memento(this.content);
    }

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

/**
 * Caretaker 备忘录管理者:负责保管备忘录对象,不读取内部状态
 */
class Caretaker {
    private Memento memento;

    public void saveMemento(Memento memento) {
        this.memento = memento;
    }

    public Memento getMemento() {
        return memento;
    }
}

// 测试客户端
public class MementoDemo {
    public static void main(String[] args) {
        Editor editor = new Editor();
        Caretaker caretaker = new Caretaker();

        // 编辑文本
        editor.setContent("第一版内容:Java设计模式");
        System.out.println("当前编辑器内容:" + editor.getContent());

        // 保存快照
        caretaker.saveMemento(editor.saveToMemento());
        System.out.println(">>> 已经保存备忘录快照");

        // 修改内容
        editor.setContent("第二版内容:备忘录模式 Memento,修改后的文字");
        System.out.println("修改后编辑器内容:" + editor.getContent());

        // 恢复快照
        editor.restoreFromMemento(caretaker.getMemento());
        System.out.println("恢复快照后内容:" + editor.getContent());
    }
}

输出结果

当前编辑器内容:第一版内容:Java设计模式
>>> 已经保存备忘录快照
修改后编辑器内容:第二版内容:备忘录模式 Memento,修改后的文字
恢复快照后内容:第一版内容:Java设计模式

扩展:多版本历史记录(保存多个快照)

Caretaker 使用 List 存储多个备忘录,实现撤销多次操作:

import java.util.ArrayList;
import java.util.List;

class CaretakerMulti {
    private final List<Memento> mementoList = new ArrayList<>();

    public void add(Memento memento) {
        mementoList.add(memento);
    }

    public Memento get(int index) {
        return mementoList.get(index);
    }
}

class MementoMultiDemo {
    public static void main(String[] args) {
        Editor editor = new Editor();
        CaretakerMulti caretaker = new CaretakerMulti();

        editor.setContent("版本1");
        caretaker.add(editor.saveToMemento());

        editor.setContent("版本2");
        caretaker.add(editor.saveToMemento());

        editor.setContent("版本3");
        System.out.println("当前:" + editor.getContent());

        // 回退到版本1
        editor.restoreFromMemento(caretaker.get(0));
        System.out.println("回退到版本1:" + editor.getContent());
    }
}

要点说明

  1. 封装保护Memento构造方法包访问权限,外部不能 new 备忘录,防止外部篡改保存的状态。

  2. 职责分离:Originator 读写状态;Memento 只存数据;Caretaker 只负责保管,不解析备忘录内容。

  3. 适用场景:撤销操作、快照备份、历史版本回退。

  4. 缺点:状态很多时备忘录对象占用内存大。


本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。

原文链接 https://www.yijunzhao.cc/archives/java-memento-pattern-example-code

欢迎访问 https://www.yijunzhao.cc/

https://www.yijunzhao.cc/