Java 编程之备忘录模式

发布于:2025-06-27 ⋅ 阅读:(17) ⋅ 点赞:(0)

前言

有时候,我们真希望人生能有“Ctrl+Z”。在日常生活中,我们经常使用“撤销”功能,例如在写 Word、画图、写代码时一不小心操作失误,就希望能回到之前的状态。这种**“状态快照 + 恢复”**机制,在设计模式中就叫做:备忘录模式(Memento Pattern)

本文将通过一个现实场景——写小说与撤销编辑操作,来贯穿讲解备忘录模式,并用 Java 代码实现一套完整的例子,让你在概念与实践中都收获满满。

一、备忘录模式是什么

定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后将其恢复。

换句话说,它是实现“撤销(Undo)”、“回退(Rollback)”、“恢复(Recover)”的核心设计模式。

二、小说家与“撤销按钮”

想象你是个小说作者,每天都在写小说的草稿。

  • 每写一段内容,你都可以“保存一下”(打个草稿快照);
  • 写崩了?你就点击“撤销”,恢复之前保存的状态;
  • 每一个“保存”其实就是一个备忘录对象(Memento)
  • 你就是“发起者(Originator)”;
  • 草稿箱(Caretaker)里存着所有的“保存记录”。

三、核心结构类比

角色名 类比于现实 作用说明
Originator 小说作者 拥有真实内容和状态,可以保存或恢复
Memento 每一段草稿 状态快照,保存了当前文本
Caretaker 草稿箱 保存多个草稿,但不关心内容细节

四、Java 实例

如下以java来实现:小说草稿的撤销与恢复

Memento:草稿快照

// 草稿状态(备忘录)
public class DraftMemento {
    private final String content;

    public DraftMemento(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}

Originator:小说作者

// 发起者,写小说的作者
public class Author {
    private String content;

    public void write(String text) {
        this.content = text;
        System.out.println("🖊️ 当前写作内容:" + content);
    }

    public DraftMemento saveDraft() {
        System.out.println("📁 保存草稿");
        return new DraftMemento(content);
    }

    public void restoreDraft(DraftMemento memento) {
        this.content = memento.getContent();
        System.out.println("↩️ 恢复到草稿:" + content);
    }

    public String getContent() {
        return content;
    }
}

Caretaker:草稿箱

import java.util.Stack;

// 草稿箱,负责保存多个版本
public class DraftCaretaker {
    private final Stack<DraftMemento> drafts = new Stack<>();

    public void save(DraftMemento draft) {
        drafts.push(draft);
    }

    public DraftMemento undo() {
        if (!drafts.isEmpty()) {
            return drafts.pop();
        }
        return null;
    }

    public boolean hasHistory() {
        return !drafts.isEmpty();
    }
}

测试主类:模拟写作与撤销

public class MementoDemo {
    public static void main(String[] args) {
        Author author = new Author();
        DraftCaretaker caretaker = new DraftCaretaker();

        author.write("故事的开始:从前有座山");
        caretaker.save(author.saveDraft());

        author.write("故事第二章:山里有个庙");
        caretaker.save(author.saveDraft());

        author.write("故事第三章:庙里住着老和尚和小和尚");

        System.out.println("\n⚠️ 写崩了!撤销!");
        if (caretaker.hasHistory()) {
            author.restoreDraft(caretaker.undo());  // 撤销到第二章
        }

        System.out.println("\n📄 当前内容:" + author.getContent());
    }
}

输出示例

🖊️ 当前写作内容:故事的开始:从前有座山
📁 保存草稿
🖊️ 当前写作内容:故事第二章:山里有个庙
📁 保存草稿
🖊️ 当前写作内容:故事第三章:庙里住着老和尚和小和尚

⚠️ 写崩了!撤销!
↩️ 恢复到草稿:故事第二章:山里有个庙

📄 当前内容:故事第二章:山里有个庙

五、UML图

在这里插入图片描述

@startuml
title 备忘录模式(Memento Pattern)UML 类图

class Author {
  - content: String
  + write(text: String): void
  + saveDraft(): DraftMemento
  + restoreDraft(memento: DraftMemento): void
  + getContent(): String
}

class DraftMemento {
  - content: String
  + getContent(): String
}

class DraftCaretaker {
  - drafts: Stack<DraftMemento>
  + save(m: DraftMemento): void
  + undo(): DraftMemento
  + hasHistory(): boolean
}

Author --> DraftMemento : 创建备份
DraftCaretaker --> DraftMemento : 保存 & 提取
Author --> DraftCaretaker : 恢复状态

六、适用场景一览

场景 描述
编辑器的撤销重做 文本编辑、画图软件
游戏存档系统 保存玩家状态,失败后恢复
数据库事务回滚 恢复操作前的状态
配置修改回滚 系统设置、软件参数

七、小结

优点:

  • 不破坏封装性,内部状态对外透明
  • 实现撤销/恢复简单灵活
  • 多状态历史管理方便

注意事项:

  • 每次保存都会占用内存,可能引起性能开销
  • 状态对象较大时,建议存储增量而非全量

备忘录模式就像我们生活中的“后悔药”,
它帮你把时间打包,瓶中封印,
等你想“回到昨天”,只需轻轻一唤。

八、参考

《23种设计模式概览》
在这里插入图片描述