【设计模式】【行为型模式】备忘录模式(Memento)

简介: 一、入门 什么是备忘录模式? 备忘录模式(Memento Pattern)是一种行为设计模式,用于在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在需要时恢复该状态。它通常用于实现撤销操作

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中... 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

🎵 当你的天空突然下了大雨,那是我在为你炸乌云

一、入门

什么是备忘录模式?

备忘录模式(Memento Pattern)是一种行为设计模式,用于在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在需要时恢复该状态。它通常用于实现撤销操作或保存对象的历史状态。

为什么需要备忘录模式?

假设我们正在开发一个简单的文本编辑器,支持以下功能:

  1. 用户可以输入文本。
  2. 用户可以保存当前文本状态。
  3. 用户可以撤销操作,恢复到之前保存的状态。

我们实现的代码如下

// 文本编辑器类
class Editor {
   
    private String content;

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

    public String getContent() {
   
        return content;
    }

    // 保存状态(直接返回内部状态)
    public String save() {
   
        return content;
    }

    // 恢复状态(直接设置内部状态)
    public void restore(String savedContent) {
   
        this.content = savedContent;
    }
}

客户端测试

// 客户端代码
public class TextEditorWithoutMemento {
   
    public static void main(String[] args) {
   
        Editor editor = new Editor();

        // 用户输入文本
        editor.setContent("First draft");
        System.out.println("Current Content: " + editor.getContent());

        // 保存状态
        String savedState = editor.save();

        // 用户修改文本
        editor.setContent("Second draft");
        System.out.println("Updated Content: " + editor.getContent());

        // 撤销操作,恢复到之前的状态
        editor.restore(savedState);
        System.out.println("Restored Content: " + editor.getContent());
    }
}

存在的问题

  1. 破坏封装性Editorcontent状态通过save()restore()方法直接暴露给外部,外部代码可以随意修改状态。
  2. 耦合性高:撤销逻辑直接依赖Editor的内部状态,如果Editor的状态结构发生变化,撤销逻辑也需要修改。
  3. 难以扩展:如果需要支持多次撤销(保存多个历史状态),代码会变得复杂且难以维护。

如何实现备忘录模式?

备忘录模式的核心角色

  1. Originator(发起人)
    • 负责创建备忘录,记录当前时刻的内部状态。
    • 可以使用备忘录恢复内部状态。
  2. Memento(备忘录)
    • 存储发起人的内部状态。
    • 通常只允许发起人访问其内部状态,以防止其他对象修改。
  3. Caretaker(管理者)
    • 负责保存备忘录,但不能修改或检查其内容。
    • 提供保存和恢复备忘录的功能。

【案例】文本编辑 - 改

image.png

Memento(备忘录)EditorMemento类,保存Editor的状态

class EditorMemento {
   
    private final String content;

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

    public String getContent() {
   
        return content;
    }
}

Originator(发起人)Editor

class Editor {
   
    private String content;

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

    public String getContent() {
   
        return content;
    }

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

    // 从备忘录恢复状态
    public void restore(EditorMemento memento) {
   
        this.content = memento.getContent();
    }
}

Caretaker(管理者)History

class History {
   
    private final List<EditorMemento> mementos = new ArrayList<>();

    public void push(EditorMemento memento) {
   
        mementos.add(memento);
    }

    public EditorMemento pop() {
   
        if (mementos.isEmpty()) {
   
            return null;
        }
        return mementos.remove(mementos.size() - 1);
    }
}

客户端代码

public class TextEditorWithMemento {
   
    public static void main(String[] args) {
   
        Editor editor = new Editor();
        History history = new History();

        // 用户输入文本
        editor.setContent("First draft");
        history.push(editor.save()); // 保存状态
        System.out.println("Current Content: " + editor.getContent());

        // 用户修改文本
        editor.setContent("Second draft");
        history.push(editor.save()); // 保存状态
        System.out.println("Updated Content: " + editor.getContent());

        // 用户再次修改文本
        editor.setContent("Third draft");
        System.out.println("Updated Content: " + editor.getContent());

        // 撤销操作
        editor.restore(history.pop()); // 恢复到第二次保存的状态
        System.out.println("Restored Content: " + editor.getContent());

        // 再次撤销操作
        editor.restore(history.pop()); // 恢复到第一次保存的状态
        System.out.println("Restored Content: " + editor.getContent());
    }
}

二、备忘录模式在框架源码中的运用

Spring 框架中的事务管理

Spring 框架中的事务管理也使用了备忘录模式的思想。在事务回滚时,Spring 需要恢复对象的状态。

备忘录(Memento)TransactionStatusTransactionStatus 保存了事务的当前状态
以下是精简版代码的

public interface TransactionStatus extends SavepointManager, Flushable {
   
    boolean isNewTransaction(); // 是否是新事务
    boolean hasSavepoint();     // 是否有保存点
    void setRollbackOnly();     // 标记事务为回滚
    boolean isRollbackOnly();   // 是否需要回滚
    boolean isCompleted();      // 事务是否已完成
}

管理者(Caretaker)PlatformTransactionManager
PlatformTransactionManager 是 Spring 事务管理的核心接口,负责管理事务的生命周期。它通过 getTransaction() 方法获取事务状态(TransactionStatus),并在事务提交或回滚时恢复状态。

public interface PlatformTransactionManager {
   
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
    void commit(TransactionStatus status) throws TransactionException;
    void rollback(TransactionStatus status) throws TransactionException;
}

发起人(Originator)TransactionTemplateSpring提供的一个工具类,用于简化事务的编程式管理。它封装了事务的执行逻辑,并在事务执行过程中创建和恢复事务状态。

public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations {
   
    private PlatformTransactionManager transactionManager;

    @Override
    public <T> T execute(TransactionCallback<T> action) throws TransactionException {
   
        // 获取事务状态
        TransactionStatus status = this.transactionManager.getTransaction(this);

        T result;
        try {
   
            // 执行业务逻辑
            result = action.doInTransaction(status);
        } catch (RuntimeException | Error ex) {
   
            // 回滚事务
            rollbackOnException(status, ex);
            throw ex;
        }

        // 提交事务
        this.transactionManager.commit(status);
        return result;
    }

    private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
   
        if (status.isNewTransaction()) {
   
            this.transactionManager.rollback(status);
        }
    }
}

三、总结

备忘录模式的优点

  1. 封装性好
    • 备忘录模式将对象的状态保存在一个独立的Memento对象中,避免了直接暴露对象的内部状态,保持了对象的封装性。
  2. 简化状态管理
    • 通过将状态管理的逻辑集中到Caretaker中,避免了状态管理代码分散在业务逻辑中,使代码更清晰、更易维护。
  3. 支持撤销/重做功能
    • 备忘录模式天然适合实现撤销和重做功能,通过保存多个 Memento 对象,可以轻松恢复到之前的状态。
  4. 扩展性强
    • 如果需要支持多次撤销或保存多个历史状态,只需在Caretaker中维护多个Memento对象即可。
  5. 解耦
    • 备忘录模式将状态保存和恢复的逻辑与业务逻辑解耦,使得代码更易于复用和扩展。

备忘录模式的缺点

  1. 内存消耗
    • 如果需要保存大量的状态或状态数据较大,备忘录模式可能会占用较多的内存。
  2. 性能开销
    • 频繁地创建和恢复Memento对象可能会带来一定的性能开销,尤其是在状态数据较大的情况下。
  3. 复杂性增加
    • 对于简单的场景,引入备忘录模式可能会增加代码的复杂性,显得“杀鸡用牛刀”。
  4. 状态暴露风险
    • 如果Memento对象的设计不当,可能会导致状态暴露给外部代码,破坏封装性。

备忘录模式的适用场景

  1. 撤销/重做功能
    • 需要实现撤销和重做功能的场景,如文本编辑器、绘图工具等。
  2. 事务管理
    • 需要保存和恢复对象状态的场景,如数据库事务管理、游戏存档等。
  3. 历史记录
    • 需要保存对象的历史状态以供后续使用的场景,如操作日志、版本控制等。
  4. 状态快照
    • 需要在某个时间点保存对象的状态,并在后续恢复的场景,如游戏中的保存点、虚拟机快照等。
  5. 复杂对象的状态管理
    • 对于状态结构复杂的对象,备忘录模式可以简化状态管理逻辑。
目录
相关文章
|
1月前
|
设计模式 网络协议 Java
【设计模式】【行为型模式】状态模式(State)
一、入门 什么是状态模式? 状态模式(State Pattern)是一种行为设计模式,允许对象在其内部状态改变时改变其行为,使其看起来像是改变了类。状态模式的核心思想是将对象的状态封装成独立的类,并将
86 16
|
1月前
|
设计模式 算法 前端开发
【设计模式】【行为型模式】职责链模式(Chain of Responsibility)
一、入门 什么是职责链模式? 职责链模式是一种行为设计模式,它允许你将请求沿着一条链传递,直到有对象处理它为止。每个对象都有机会处理请求,或者将其传递给链中的下一个对象。 为什么需要职责链模式? 使用
88 16
|
3月前
|
设计模式 存储 Java
【再谈设计模式】备忘录模式~对象状态的守护者
备忘录模式属于行为型设计模式。它的主要目的是在不破坏对象封装性的前提下,捕获并外部化一个对象的内部状态,以便之后可以将该对象恢复到这个状态。原发器(Originator):创建一个备忘录,用于记录当前时刻它的内部状态。原发器还可以使用备忘录来恢复其内部状态。备忘录(Memento):存储原发器对象的内部状态。备忘录应该防止原发器以外的其他对象访问其内部状态。负责人(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
238 82
|
1月前
|
设计模式 消息中间件 Java
【设计模式】【行为型模式】命令模式(Command)
一、入门 什么是命令模式? 命令模式是一种行为设计模式,它将请求或操作封装为对象,从而使你可以用不同的请求对客户进行参数化,并支持请求的排队、记录、撤销等操作。 命令模式的核心是将“请求”封装为独立的
104 15
|
1月前
|
设计模式 算法 搜索推荐
【设计模式】【行为型模式】策略模式(Strategy)
一、入门 什么是策略模式? 策略模式是一种行为设计模式,允许在运行时选择算法或行为。它将算法封装在独立的类中,使得它们可以互换,而不影响客户端代码。 为什么需要策略模式? 策略模式的主要目的是解决算法
64 14
|
1月前
|
设计模式 Java 编译器
【设计模式】【行为型模式】解释器模式(Interpreter)
一、入门 什么是解释器模式? 解释器模式(Interpreter Pattern)是一种行为设计模式,用于定义语言的语法表示,并提供一个解释器来处理该语法。它通常用于需要解释和执行特定语言或表达式的场
65 11
|
1月前
|
设计模式 存储 JavaScript
【设计模式】【行为型模式】迭代器模式(Iterator)
一、入门 什么是迭代器模式? 迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种顺序访问聚合对象中元素的方法,而不需要暴露其底层表示。迭代器模式将遍历逻辑从聚合对象中分离出
71 11
|
1月前
|
设计模式 数据采集 算法
【设计模式】【行为型模式】模板方法模式(Template Method)
一、入门 1.1、什么是模板方法模式? 模板模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤。
73 13
|
1月前
|
设计模式 XML JSON
【设计模式】【行为型模式】访问者模式(Visitor)
一、入门 什么是访问者模式? 访问者模式(Visitor Pattern)是一种行为设计模式,允许你将算法与对象结构分离。通过这种方式,可以在不改变对象结构的情况下,向对象结构中的元素添加新的操作。
85 10
|
1月前
|
设计模式 Java 程序员
【设计模式】【行为型模式】中介者模式(Mediator)
一、入门 什么是中介者模式? 中介者模式(Mediator Pattern)是一种行为设计模式,旨在减少对象之间的直接依赖,通过引入一个中介者对象来协调多个对象之间的交互。这种模式特别适用于对象间存在
75 9