设计模式-备忘录模式

# 备忘录模式

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...

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

相关推荐
骄马之死3 小时前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
GoGeekBaird4 小时前
Anthropic技能"(Skills)的经验分享
后端
王码码20354 小时前
多台服务器怎么统一看状态?Beszel 轻量监控,搭起来不费事
运维·服务器·后端·安全·阿里云·接口·web
郑洁文4 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
螺丝钉code5 小时前
JAVA项目 Claude code CLAUDE.md 到底应该怎么写
java·人工智能·claude code
Cosolar5 小时前
LlamaIndex 文档解析与分块策略深度解析
人工智能·面试·架构
指令集梦境6 小时前
Cursor + Spring Boot实战:从零写一个RESTful API
spring boot·后端·restful
摇滚侠6 小时前
Maven 入门+高深 单一架构案例 54-59
java·架构·maven·intellij-idea
VidDown6 小时前
Webhook 调试器:让第三方回调“原形毕露”
java·开发语言·javascript·编辑器·postman
码云之上6 小时前
聊聊如何设计一个高效、稳定的 Node.js 接入层
前端·后端·node.js