JAVA设计模式之备忘录模式详解

备忘录模式

1 备忘录模式介绍

备忘录模式提供了一种对象状态的撤销实现机制,当系统中某一个对象需要恢复到某一历史状态时可以使用备忘录模式进行设计.
在这里插入图片描述

很多软件都提供了撤销(Undo)操作,如 Word、记事本、Photoshop、IDEA等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态;还有在 浏览器 中的后退键、数据库事务管理中的回滚操作、玩游戏时的中间结果存档功能、数据库与操作系统的备份操作、棋类游戏中的悔棋功能等都属于这类。

备忘录模式(memento pattern)定义: 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态.

2 备忘录模式原理

在这里插入图片描述

备忘录模式的主要角色如下:

  • 发起人(Originator)角色:状态需要被记录的元对象类, 记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  • 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  • 看护人(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

3 备忘录模式实现

下面我们再来看看 UML 对应的代码实现。首先,我们创建原始对象 Originator,对象中有四个属性,分别是 state 用于显示当前对象状态,id、name、phone 用来模拟业务属性,并添加 get、set 方法、create() 方法用于创建备份对象,restore(memento) 用于恢复对象状态。

/*** 发起人类**/
public class Originator {private String state = "原始对象";private String id;private String name;private String phone;public Originator() {}//创建备忘录对象public Memento create(){return new Memento(id,name,phone);}//恢复对象状态public void restore(Memento m){this.state = m.getState();this.id = m.getId();this.name = m.getName();this.phone = m.getPhone();}public String getState() {return state;}public void setState(String state) {this.state = state;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}@Overridepublic String toString() {return "Originator{" +"state='" + state + '\'' +", id='" + id + '\'' +", name='" + name + '\'' +", phone='" + phone + '\'' +'}';}
}/*** 备忘录对象*     访问权限为: 默认,也就是同包下可见(保证只有发起者类可以访问备忘录类)**/
class Memento {private String state = "从备份对象恢复为原始对象";private String id;private String name;private String phone;public Memento() {}public Memento(String id, String name, String phone) {this.id = id;this.name = name;this.phone = phone;}//get、set、toString......
}/*** 负责人类-保存备忘录对象**/
public class Caretaker {private Memento memento;public Memento getMemento() {return memento;}public void setMemento(Memento memento) {this.memento = memento;}
}public class Client {public static void main(String[] args) {//创建发起人对象Originator originator = new Originator();originator.setId("1");originator.setName("spike");originator.setPhone("13512341234");System.out.println("=============" + originator);//创建负责人对象,并保存备忘录对象Caretaker caretaker = new Caretaker();caretaker.setMemento(originator.create());//修改originator.setName("update");System.out.println("=============" + originator);//从负责人对象中获取备忘录对象,实现撤销originator.restore(caretaker.getMemento());System.out.println("=============" + originator);}
}

4 备忘录模式应用实例

设计一个收集水果和获取金钱数的掷骰子游戏,游戏规则如下

  1. 游戏玩家通过扔骰子来决定下一个状态
  2. 当点数为1,玩家金钱增加
  3. 当点数为2,玩家金钱减少
  4. 当点数为6,玩家会得到水果
  5. 当钱消耗到一定程度,就恢复到初始状态
  • Memento类: 表示玩家的状态
/*** Memento 表示状态**/
public class Memento {int money;    //所持金钱ArrayList fruits; //获得的水果//构造函数Memento(int money) {this.money = money;this.fruits = new ArrayList();}//获取当前玩家所有的金钱int getMoney() {return money;}//获取当前玩家所有的水果List getFruits() {return (List)fruits.clone();}//添加水果void addFruit(String fruit){fruits.add(fruit);}
}
  • Player玩家类,只要玩家的金币还够,就会一直进行游戏,在该类中会设置一个createMemento方法,其作用是保存当前玩家状态.还会包含一个restore撤销方法,相当于复活操作.
package com.mashibing.memento.example02;import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class Player {private int money;      //所持金钱private List<String> fruits = new ArrayList();  //获得的水果private Random random = new Random();   //随机数对象private static String[] fruitsName={    //表示水果种类的数组"苹果","葡萄","香蕉","橘子"};//构造方法public Player(int money) {this.money = money;}//获取当前所持有的金钱public int getMoney() {return money;}//获取一个水果public String getFruit() {String prefix = "";if (random.nextBoolean()) {prefix = "好吃的";}//从数组中获取水果String f = fruitsName[random.nextInt(fruitsName.length)];return prefix + f;}//掷骰子游戏public void yacht(){int dice = random.nextInt(6) + 1;   //掷骰子if(dice == 1){money += 100;System.out.println("所持有的金钱增加了..");}else if(dice == 2){money /= 2;System.out.println("所持有的金钱减半..");}else if(dice == 6){   //获取水果String fruit = getFruit();System.out.println("获得了水果: " + fruit);fruits.add(fruit);}else{//骰子结果为3、4、5System.out.println("无效数字,继续投掷");}}//拍摄快照public Memento createMemento(){Memento memento = new Memento(money);for (String fruit : fruits) {if(fruit.startsWith("好吃的")){memento.addFruit(fruit);}}return memento;}//撤销方法public void restore(Memento memento){this.money = memento.money;this.fruits = memento.getFruits();}@Overridepublic String toString() {return "Player{" +"money=" + money +", fruits=" + fruits +'}';}
}
  • 测试: 由于引入了备忘录模式,可以保存某个时间点的玩家状态,这样就可以对玩家进行复活操作.
public class MainApp {public static void main(String[] args) throws InterruptedException {Player player = new Player(100);        //最初所持的金钱数Memento memento = player.createMemento();       //保存最初状态for (int i = 0; i < 100; i++) {//显示扔骰子的次数System.out.println("=====" + i);//显示当前状态System.out.println("当前状态: " + player);//开启游戏player.yacht();System.out.println("所持有的金钱为: " + player.getMoney() + " 元");//决定如何操作Mementoif(player.getMoney() > memento.getMoney()){System.out.println("赚到金币,保存当前状态,继续游戏!");memento = player.createMemento();}else if(player.getMoney() < memento.getMoney() / 2){System.out.println("所持金币不多了,将游戏恢复到初始状态!");player.restore(memento);}Thread.sleep(1000);System.out.println("");}}
}

5 备忘录模式总结

1 备忘录模式的优点
  1. 提供了一种状态恢复的实现机制,使得用户可以方便的回到一个特定的历史步骤,当新的状态无效或者存在问题的时候,可以使用暂时存储起来的备忘录将状态复原.
  2. 备忘录实现了对信息的封装,一个备忘录对象是一种发起者对象状态的表示,不会被其他代码所改动.备忘录保存了发起者的状态,采用集合来存储备忘录可以实现多次撤销的操作
2 备忘录模式的缺点
  • 资源消耗过大,如果需要保存的发起者类的成员变量比较多, 就不可避免的需要占用大量的存储空间,每保存一次对象的状态,都需要消耗一定系统资源
3 备忘录模式使用场景
  1. 需要保存一个对象在某一时刻的状态时,可以使用备忘录模式.
  2. 不希望外界直接访问对象内部状态时.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/680259.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stable Diffusion 模型下载:majicMIX fantasy 麦橘幻想

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十

【Web】Redis未授权访问漏洞学习笔记

目录 简介 靶机配置 Redis持久化 Redis动态修改配置 webshell 反弹shell Redis写入反弹shell任务 加固方案 简介 Redis&#xff08;Remote Dictionary Server 远程字典服务器&#xff09;是一个开源的内存数据库&#xff0c;也被称为数据结构服务器&#xff0c;它支持…

SCI论文作图规范

SCI论文作图规范包括以下几个方面&#xff1a; 一、图片格式 SCI论文通常接受的图片格式包括TIFF、EPS和PDF等。其中&#xff0c;TIFF格式是一种高质量的图像格式&#xff0c;适用于需要高分辨率和颜色准确性的图片&#xff1b;EPS格式是一种矢量图形格式&#xff0c;适用于需…

位运算+leetcode ( 2 )

题一&#xff1a;只出现一次的数字&#xff08;1&#xff09; 1.链接 136. 只出现一次的数字 - 力扣&#xff08;LeetCode&#xff09; 2.思想 借用位运算中异或操作符的特点&#xff0c;a^a0&#xff0c;0^aa先定义一个sum0就用一个循环来遍历这个数组&#xff0c;每次都进行…

Google Cloud 2024 年报告重点介绍了关键的网络威胁和防御

Google Cloud 的 2024 年威胁范围报告预测了云安全的主要风险&#xff0c;并提出了加强防御的策略。 该报告由 Google 安全专家撰写&#xff0c;为寻求预测和应对不断变化的网络安全威胁的云客户提供了宝贵的资源。 该报告强调&#xff0c;凭证滥用、加密货币挖矿、勒索软件和…

GO 的 Web 开发系列(五)—— 使用 Swagger 生成一份好看的接口文档

经过前面的文章&#xff0c;已经完成了 Web 系统基础功能的搭建&#xff0c;也实现了 API 接口、HTML 模板渲染等功能。接下来要做的就是使用 Swagger 工具&#xff0c;为这些 Api 接口生成一份好看的接口文档。 一、写注释 注释是 Swagger 的灵魂&#xff0c;Swagger 是通过…

C++ 广度优先搜索(bfs)(五十四)【第一篇】

今天我们来学习一下一个新的搜索&#xff0c;广度优先搜索。 1.广度优先搜索的前提 队列&#xff08;queue&#xff09; 是一种 操作受限制 的线性表&#xff0c;其限制&#xff1a; 只允许从表的前端&#xff08;front&#xff09;进行删除操作&#xff1b; 只允许在表的后端…

嵌入式Qt Qt 中的坐标系统

一.Qt中的坐标系统 实验1&#xff1a;窗口坐标大小 #include <QtGui/QApplication> #include <QPushButton> #include <QDebug> #include "widget.h" int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();qDebug()&…

[JavaWeb玩耍日记]Maven的安装与使用

目录 一.作用 二.安装 三.使用 2.对项目使用compile命令进行编译,看看新的文件会在哪里产生&#xff1f; 3.需要认识的命令 4.Maven对项目执行不同命令的生命周期特点&#xff1f; 5.如何导入工程外的Maven&#xff1f; 6.如何直观地查看Maven导入了哪些工程或哪些jar包…

蓝桥杯嵌入式第六届真题(完成)STM32G431

蓝桥杯嵌入式第六届真题&#xff08;完成&#xff09;STM32G431 题目部分 相关文件 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program b…

LeetCode:69.x的平方根

嗨嗨嗨&#xff0c;二分又来了&#xff0c;淦它&#xff0c; 这个题官解是&#xff0c;C函数法&#xff0c;二分&#xff0c;和牛顿迭代法&#xff08;暂且搁置&#xff09;&#xff0c; 当然还有暴力&#xff08;不必讨论&#xff0c;就从0开始一个一个试&#xff09;&#…

Git 消除对某个文件的追踪

参考&#xff1a; &#xff08;尚未验证他的该方法&#xff09; https://www.golinuxcloud.com/git-remove-file-from-tracking/https://www.golinuxcloud.com/git-remove-file-from-tracking/

计网day1

RTT&#xff1a;往返传播时延&#xff08;越大&#xff0c;游戏延迟&#xff09; 一.算机网络概念 网络&#xff1a;网样的东西&#xff0c;网状系统 计算机网络&#xff1a;是一个将分散得、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功…

[疑难杂症2024-001] java多线程运行时遇到java.util.ConcurrentModificationException的解决方案

本文由Markdown语法编辑器编辑完成。 1.背景 由于近日在改进一个医学图像的收图服务。之前的版本&#xff0c;我们采用了pynetdicom的服务。 https://pydicom.github.io/pynetdicom/stable/ 它的介绍为: pynetdicom is a pure Python package that implements the DICOM net…

基于大语言模型的AI Agents

代理&#xff08;Agent&#xff09;指能自主感知环境并采取行动实现目标的智能体。基于大语言模型&#xff08;LLM&#xff09;的 AI Agent 利用 LLM 进行记忆检索、决策推理和行动顺序选择等&#xff0c;把Agent的智能程度提升到了新的高度。LLM驱动的Agent具体是怎么做的呢&a…

Hive调优——explain执行计划

一、explain查询计划概述 explain将Hive SQL 语句的实现步骤、依赖关系进行解析&#xff0c;帮助用户理解一条HQL 语句在底层是如何实现数据的查询及处理&#xff0c;通过分析执行计划来达到Hive 调优&#xff0c;数据倾斜排查等目的。 https://cwiki.apache.org/confluence/d…

Java安全 URLDNS链分析

Java安全 URLDNS链分析 什么是URLDNS链URLDNS链分析调用链路HashMap类分析URL类分析 exp编写思路整理初步expexp改进最终exp 什么是URLDNS链 URLDNS链是Java安全中比较简单的一条利用链&#xff0c;无需使用任何第三方库&#xff0c;全依靠Java内置的一些类实现&#xff0c;但…

网络专栏目录

大家好我是苏麟 , 这是网络专栏目录 . 图解网络 资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 图解网络目录 基础篇 基础篇 TCP/IP网络模型有几层? : TCP/IP网络模型 键入网址到页面显示,期间发生了什么? : 键入网址到页面显示,期间发生了什么 现阶…

C++:面向对象——类的构造

1.1学会面向对象的编程思想 面向对象的英文缩写是OO&#xff0c;它是一种设计思想。 面向对象有3大特点&#xff1a;封装、继承和多态。 1.封装 封装有两个作用&#xff0c;一个是将不同的小对象封装成一个大对象&#xff1b;另外一个是把一部分内部属性和功能对外界屏蔽。…

数据结构哈希表

这里个大家用数组来模拟哈希表 法一&#xff1a;拉链法 法二&#xff1a;开放寻址法 /** Project: 11_哈希表* File Created:Sunday, January 17th 2021, 2:11:23 pm* Author: Bug-Free* Problem:AcWing 840. 模拟散列表 拉链法*/ #include <cstring> #include <iostr…