设计模式-备忘录模式

# 备忘录模式

1.简介

备忘录模式是一种行为设计模式,允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。

简单的来说就是在某一时刻把当前状态记录下来,以后可以选择性的再恢复到某次保存的状态。

例如游戏中的存档、编辑器中的 crtl+z、浏览器中的后退、数据库的事务管理等等。

2.UML图

  • **原发器(Originator):**类可以生成自身状态的快找,也可以在需要时通过快照恢复自身状态。
  • **备忘录(Memento):**是原发器状态快照的值对象。通常做法是将备忘录设为不可变得,并通过构造函数一次性传递数据。
  • **负责人(Caretaker):**仅知道 何时、为何 捕捉原发器的状态,以及何时恢复状态。 负责人通过保存备忘录栈来记录原发器的历史状态,当原发器需要回溯历史状态时,负责人将从栈中获取最顶部的备忘录,并将其传给原发器的恢复方法。
  • 在该实现方法中,备忘录类将被嵌套在原发器中。这样原发器就可以访问备忘录的成员变量和方法,即使这些方法被声明为私有。另一方面,负责人对于备忘录的成员变量和方法的访问权限非常有限;它们只能在栈中保存备忘录,而不能修改其状态。

3.代码示例

我们来写一个游戏存档的例子。

首先定义Originator(游戏类):

我们需要保存和读取游戏进度,它内部提供了两个方法,一个是对外提供备忘录(封装了要恢复的内部状态)。另一个是从外接受备忘录,用来恢复内部状态。

java 复制代码
package com.gs.designmodel.memento;

/**
 * @author: Gaos
 * @Date: 2023-08-22 18:35
 **/
public class GameOriginator {

    private int currentScore;

    /**
     * 将需要保存的状态封装在Memento里对外提供
     * @return
     */
    public GameProgressMemento saveProcess() {
        return new GameProgressMemento(currentScore);
    }

    /**
     * 通过从外部接收的Memento恢复状态
     * @param memento
     */
    public void restoreProcess(GameProgressMemento memento) {
        currentScore = memento.getScore();
    }

    public void playGame() {
        System.out.println("Game Begin---");
        System.out.println("当前分数为: " + currentScore);
        System.out.println("击杀小兵得一分");
        currentScore++;
        System.out.println("总分为: " + currentScore);
    }

    public void  exitGame() {
        System.out.println("退出游戏");
        currentScore = 0;
        System.out.println("Game End-----");
    }
}

构建Memento(备忘录):

就只是一个简单的实体类,不包含业务逻辑只包含数据状态,结构由要保存的状态类决定,我们这里只保存一个游戏分数。

java 复制代码
package com.gs.designmodel.memento;

/**
 * @author: Gaos
 * @Date: 2023-08-22 18:38
 **/
public class GameProgressMemento {

    private int score;

    public GameProgressMemento(int score) {
        this.score = score;
    }

    public int getScore() {
        return score;
    }
}

构建CareTaker(负责人):

CareTaker相对于 Originator来说是一个外部组件,它帮助 Originator保存了状态。

java 复制代码
package com.gs.designmodel.memento;

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

/**
 * @author: Gaos
 * @Date: 2023-08-22 18:38
 **/
public class GameCareTaker {

    private List<GameProgressMemento> mementos  = new ArrayList<>();

    /**
     * 保存状态
     * @param memento
     */
    public void saveMemento(GameProgressMemento memento) {
        this.mementos.add(memento);
    }

    /**
     * 恢复状态
     * @param index
     * @return
     */
    public GameProgressMemento getMemento(int index) {
        return this.mementos.get(index);
    }
}

测试类:

java 复制代码
package com.gs.designmodel.memento;

/**
 * @author: Gaos
 * @Date: 2023-08-22 18:46
 **/
public class Test {
    public static void main(String[] args) {
        GameOriginator originator = new GameOriginator();
        GameCareTaker careTaker = new GameCareTaker();
        // 客户端需要维护一个指针和备忘录的次序相对应
        int index = 0;
        // 玩游戏
        originator.playGame();
        // 保存进度
        careTaker.saveMemento(originator.saveProcess());
        // 退出游戏
        originator.exitGame();

        // 重新打开游戏恢复进度
        originator.restoreProcess(careTaker.getMemento(index));
        originator.playGame();
    }
}

结果:

sql 复制代码
Game Begin---
当前分数为: 0
击杀小兵得一分
总分为: 1
退出游戏
Game End-----
Game Begin---
当前分数为: 1
击杀小兵得一分
总分为: 2

4.总结

当你需要创建对象状态快照来恢复其之前的状态时,你可以使用备忘录模式。当对象的安全性被突破时你可以使用备忘录模式。(备忘录让对象自行负责创建其状态的快找,其他任何对象都不能读取快照,这保障了数据的安全性)

你可以使用 命令模式和备忘录模式来实现撤销,命令对目标对象执行各种不同的操作,备忘录用来保存一条命令执行前盖对象的状态。但是如果客户端太过于频繁的创建备忘录,程序将消耗大量内存,同时 负责人(CareTaker)必须根据原发器的生命周期,这样才能销毁弃用的备忘录。

参考文章:

refactoringguru.cn/design-patt...

blog.csdn.net/ShuSheng000...

希望这篇文章对大家有所帮助,您的赞和收藏是对我最大的支持和认可!

相关推荐
Joy T3 小时前
Agent 确定性上下文设计:从 Prompt 参数注入到能力分层
java·开发语言·微服务·架构·prompt·agent context
m0_587383006 小时前
广州 24 小时自助健身房解决方案技术实现与实战指南
java·spring·小程序·架构·需求分析
·云扬·7 小时前
Prompt 工程与安全:从 System 设计到注入防御
java·人工智能·安全·ai·prompt
怕浪猫7 小时前
2028编程圈很火的10个Skills
算法·面试·github
代码不停7 小时前
自动化测试(java)
java·开发语言·selenium·自动化
行百里er8 小时前
Redis 完结篇——Redis 热点问题在 Spring Boot 项目中实战
redis·后端
高频因子挖掘机9 小时前
只取最近 60 个交易日,却每次拉全历史:量化脚本变慢的原因与改法
后端·github·api
鬼手点金9 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
孟健10 小时前
从5000亿Token到83%字节匹配:AI逆向工程与重构的工程闭环实践
后端·架构·ai编程
paopaokaka_luck10 小时前
滑雪场管理系统(AI智能助手流式对话,ECharts 运营数据分析、教练、雪具与场地一体化预约,钱包支付退款、订单核销与服务评价)
java·人工智能·spring boot·网络协议·数据分析·echarts