1. 设计模式之备忘录模式:将中间数据暂存之后再恢复

1.1. 介绍

备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象,备忘录模式属于行为型模式

备忘录模式允许在不破坏封装性的前提下,捕获和恢复对象的内部状态。

适合场景,当需要提供一种暂存逻辑,可以供撤销恢复等操作。实际项目中,例如各个系统直接通过 MQ 交互,当 MQ 异常时,各个系统通过该模式将数据存储在磁盘中,MQ 恢复后再将磁盘数据发送到 MQ。

备忘录模式 vs 原型模式

对比维度 备忘录模式 原型模式
目的 保存和恢复对象状态。 通过克隆创建新对象。
状态访问权 原发器可访问备忘录内部状态。 克隆对象完全独立。
典型应用 撤销操作、游戏存档。 对象复制、性能优化。

应用场景

  1. 撤销/重做功能:文本编辑器、绘图软件、数据库事务回滚。

  2. 游戏存档/读档:保存玩家进度、角色状态。

  3. 配置快照:系统配置的备份与恢复。

  4. 状态回滚:微服务中的状态补偿(如Saga模式)。

优缺点及建议

优点
1.提供可回溯的状态恢复机制。
2.不破坏封装性,状态安全存储。
3.支持撤销/重做等高级功能。

缺点
1.频繁保存状态可能占用大量内存。
2.深拷贝复杂对象可能影响性能。

使用建议
1.在需要保存和恢复数据状态的场景中使用备忘录模式。
2.考虑使用原型模式结合备忘录模式,以节约内存。

注意事项
1.简单场景:直接保存基本类型或字符串状态。
2.复杂场景:使用序列化实现深拷贝(需确保对象可序列化)。
3.性能敏感场景:结合增量备份(如只保存变化的字段)。

1.2. 实现及相关代码

假设有一个业务,产生中间数据,基于中间数据执行 A 逻辑,然后又基于中间数据执行 B 逻辑。

1.2.1. 相关代码

接口及数据对象

public interface Memento {}

public static class Originator {
    private String state;

    public void prepare() {
        this.state = "中间数据";
    }

    public void executeA() {
        System.out.println("基于中间数据【" + state +"】执行了A方法的逻辑");
        // 将state所代表的中间数据做出了修改
        state += ",A方法的结果数据";
    }

    public void executeB() {
        System.out.println("基于中间数据【" + state +"】执行了B方法的逻辑");
        state += ",B方法的结果数据";
    }

    public Memento createMemento() {
        return new MementoImpl(state);
    }

    public void setMemento(Memento memento) {
        MementoImpl mementoImpl = (MementoImpl)memento;
        this.state = mementoImpl.getState();
    }

    private static class MementoImpl implements Memento {
        private String state;

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

        public String getState() {
            return state;
        }
    }
}

public static class Caretaker {
    private Memento memento;

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

    public Memento retrieveMemento() {
        return this.memento;
    }
}

调用方法

public static void main(String[] args) {
    Originator originator = new Originator();

    // 准备好了中间数据
    originator.prepare();
    // 将中间数据保存到备忘录中去
    Memento memento = originator.createMemento();
    // 将备忘录保存到备忘录管理器中去
    Caretaker caretaker = new Caretaker();
    caretaker.saveMemento(memento);
    // 基于中间数据执行了A方法,但是此时中间数据已经改变了
    originator.executeA();
    // 从备忘录管理器中获取备忘录
    memento = caretaker.retrieveMemento();
    // 将备忘录中保存好的中间数据重新设置到原发器中去,就将中间数据恢复成了之前备忘的状态
    originator.setMemento(memento);
    // 接着再次执行方法B
    originator.executeB();
}

results matching ""

    No results matching ""