【设计模式--行为型--备忘录模式】

设计模式--行为型--备忘录模式

    • 备忘录模式
      • 定义
      • 结构
      • 案例实现
        • 白箱备忘录模式
        • 黑箱备忘录模式
      • 优缺点
      • 使用场景

备忘录模式

定义

又叫快照模式,在不破坏封装性的前提下,捕获一个对象的对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。

结构

  • 发起人角色(Originator):记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  • 备忘录角色(Memento):负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人
  • 管理者角色(Caretaker):对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改
    • 备忘录有两个等效接口:
    • 窄接口:管理者对象(和其他发起人对象之外的任何对象)看到的是备忘录的窄接口,这个窄接口只允许他把备忘录对象传递给其他的对象。
    • 宽接口:与管理者看到的窄接口相反,发起人对象可以看到一个宽接口,这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象内部状态。

案例实现

游戏保存,游戏角色有生命力,攻击力,防御力等数据,模拟玩家打boss前的保存机制,失败后可以返回到进入boss关之前的状态
实现上述案例,有两种方式

  • 白箱备忘录
  • 黑箱备忘录
白箱备忘录模式

备忘录角色对任何对象都提供一个接口,即宽接口,备忘录角色内部所存储的状态就对所有对象公开。类图如下:
在这里插入图片描述

/*** 游戏角色类  发起人角色*/
public class GameRole {private int vit; // 生命private int atk; // 攻击力private int def; // 防御力// 初始化内部状态public void initState() {this.vit = 100;this.atk = 100;this.def = 100;}// 战斗public void fight() {this.vit = 0;this.atk = 100;this.def = 100;}// 保存角色状态public RoleStateMemento saveState() {return new RoleStateMemento(vit, atk, def);}// 恢复角色到初始状态public void recoverState(RoleStateMemento roleStatusMemento) {// 将备忘录中的数据赋值给当前对象this.vit = roleStatusMemento.getVit();this.atk = roleStatusMemento.getAtk();this.def = roleStatusMemento.getDef();}// 展示状态功能public void stateDisplay() {System.out.println("角色生命:" + vit);System.out.println("角色攻击:" + atk);System.out.println("角色防御:" + def);}public int getVit() {return vit;}public void setVit(int vit) {this.vit = vit;}public int getAtk() {return atk;}public void setAtk(int atk) {this.atk = atk;}public int getDef() {return def;}public void setDef(int def) {this.def = def;}
}
public class RoleStateMemento {private int vit; // 生命private int atk; // 攻击力private int def; // 防御力public RoleStateMemento() {}public RoleStateMemento(int vit, int atk, int def) {this.vit = vit;this.atk = atk;this.def = def;}public int getVit() {return vit;}public void setVit(int vit) {this.vit = vit;}public int getAtk() {return atk;}public void setAtk(int atk) {this.atk = atk;}public int getDef() {return def;}public void setDef(int def) {this.def = def;}
}
/*** 备忘录对象管理对象*/
public class RoleStateCaretaker {// 声明RoleStateMemento类型的变量private RoleStateMemento roleStatusMemento;public RoleStateMemento getRoleStatusMemento() {return roleStatusMemento;}public void setRoleStatusMemento(RoleStateMemento roleStatusMemento) {this.roleStatusMemento = roleStatusMemento;}
}
public class Test01 {public static void main(String[] args) {// 创建游戏角色对象GameRole gameRole = new GameRole();System.out.println("---boss关卡前---");gameRole.initState();gameRole.stateDisplay();// 将游戏角色内部状态进行备份// 创建管理者对象RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();roleStateCaretaker.setRoleStatusMemento(gameRole.saveState());System.out.println("---挑战boss---");gameRole.fight();gameRole.stateDisplay();System.out.println("---生命为0,boss关挑战失败,回到boss关卡前---");gameRole.recoverState(roleStateCaretaker.getRoleStatusMemento());gameRole.stateDisplay();}
}

在这里插入图片描述

白箱备忘录模式是破坏封装性的,但是通过程序员的自律,同样可以在一定程度上实现模式的大部分用意

黑箱备忘录模式

备忘录角色对发起人提供一个宽接口,而为其他对象提供一个窄接口。在JAVA语言中,实现双重接口的办法就是将备忘录类设计成发起人类的内部成员类。将RoleStateMemento设为GameRole的内部类,从而将RoleStateMemento对象封装在GameRole里面;在外面提供一个标识接口Memento给RoleStateCaretaker及其他对象使用。这样GameRole类看到的是RoleStateMemento所有的接口,而RoleStateCaretaker及其他对象看到的仅仅是标识接口Memento所暴露出来的接口,从而维护了封装性。

在这里插入图片描述

/*** 备忘录接口 对外提供窄接口*/
public interface Memento {
}
/*** 游戏角色类  发起人角色*/
public class GameRole {private int vit; // 生命private int atk; // 攻击力private int def; // 防御力// 初始化内部状态public void initState() {this.vit = 100;this.atk = 100;this.def = 100;}// 战斗public void fight() {this.vit = 0;this.atk = 100;this.def = 100;}// 保存角色状态public Memento saveState() {return new RoleStateMemento(vit, atk, def);}// 恢复角色到初始状态public void recoverState(Memento memento) {RoleStateMemento roleStatusMemento = (RoleStateMemento) memento;// 将备忘录中的数据赋值给当前对象this.vit = roleStatusMemento.getVit();this.atk = roleStatusMemento.getAtk();this.def = roleStatusMemento.getDef();}// 展示状态功能public void stateDisplay() {System.out.println("角色生命:" + vit);System.out.println("角色攻击:" + atk);System.out.println("角色防御:" + def);}public int getVit() {return vit;}public void setVit(int vit) {this.vit = vit;}public int getAtk() {return atk;}public void setAtk(int atk) {this.atk = atk;}public int getDef() {return def;}public void setDef(int def) {this.def = def;}// 私有的成员内部类private class RoleStateMemento implements Memento{private int vit; // 生命private int atk; // 攻击力private int def; // 防御力public RoleStateMemento() {}public RoleStateMemento(int vit, int atk, int def) {this.vit = vit;this.atk = atk;this.def = def;}public int getVit() {return vit;}public void setVit(int vit) {this.vit = vit;}public int getAtk() {return atk;}public void setAtk(int atk) {this.atk = atk;}public int getDef() {return def;}public void setDef(int def) {this.def = def;}}
}
/*** 备忘录对象管理对象*/
public class RoleStateCaretaker {// 声明RoleStateMemento类型的变量private Memento memento;public Memento getMemento() {return memento;}public void setMemento(Memento memento) {this.memento = memento;}
}
public class Test01 {public static void main(String[] args) {// 创建游戏角色对象GameRole gameRole = new GameRole();System.out.println("---boss关卡前---");gameRole.initState();gameRole.stateDisplay();// 将游戏角色内部状态进行备份// 创建管理者对象RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();roleStateCaretaker.setMemento(gameRole.saveState());System.out.println("---挑战boss---");gameRole.fight();gameRole.stateDisplay();System.out.println("---生命为0,boss关挑战失败,回到boss关卡前---");gameRole.recoverState(roleStateCaretaker.getMemento());gameRole.stateDisplay();}
}

在这里插入图片描述

优缺点

  • 优点
    • 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史状态。
    • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息
    • 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
  • 缺点
    • 资源消耗大,如果要保存的内部状态信息过多或者特别频繁,将会占用较大的内存资源。

使用场景

  • 需要保存与恢复数据的场景,例如游戏的存档功能。
  • 需要提供一个可回滚操作的场景。

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

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

相关文章

Python控制Excel自动刷新页面

比如我们有一个待刷新的Excel叫测试.xlsx 这里我们使用python控制Excel的应用来直接刷新相关页面: 传入的Excel路径需要是完整的路径,否则会提示找不到:pywintypes.com_error: (-2147352567, 发生意外。, (0, Microsoft Excel, 抱歉&#x…

常用数据库的分页语句(mySQL、oracle、PostgreSQL、SQL Server)

目录 ORACLE MySQL PostgreSQL SQL Server ORACLE SELECT * FROM (SELECT t.*, ROWNUM AS rnFROM (SELECT * FROM 表名 ORDER BY 排序字段) tWHERE ROWNUM < 结束行数 ) WHERE rn > 开始行数; 其中&#xff0c;表名是你要查询的表名&#xff0c;排序字段是你希望按…

Java 自定义注解

Java 自定义注解&#xff0c; 以及interface Target Retention Around Before After ProceedingJoinPoint JoinPoint 等用法 注解应用非常广泛&#xff0c;我们自定义注解能简化开发各种各种业务 一、关键字解释 (1) 定义注解时&#xff0c;关键字 interface 来表示注解类的类…

Spring Boot学习随笔- 实现AOP(JoinPoint、ProceedingJoinPoint、自定义注解类实现切面)

学习视频&#xff1a;【编程不良人】2021年SpringBoot最新最全教程 第十一章、AOP 11.1 为什么要使用AOP 问题 现有业务层开发存在问题 额外功能代码存在大量冗余每个方法都需要书写一遍额外功能代码不利于项目维护 Spring中的AOP AOP&#xff1a;Aspect 切面 Oriented 面向…

前端面试题(计算机网络):常见的HTTP请求头和响应头

前端面试题&#xff08;计算机网络&#xff09;&#xff1a;常见的HTTP请求头和响应头 HTTP Request Header 常见的请求头&#xff1a;HTTP Responses Header 常见的响应头&#xff1a;常见的 Content-Type 属性值有以下四种&#xff1a; HTTP Request Header 常见的请求头&…

竞赛保研 python 机器视觉 车牌识别 - opencv 深度学习 机器学习

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于python 机器视觉 的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 &#x1f9ff; 更多资…

【Python 基础】-- 在 mac OS 中安装 多个 python 版本

目录 1、需求 2、实现 2.1 安装 pyenv 2.2 安装 pyenv-virtualenv 2.3 配置环境变量 2.4 创建 python 3.9.9 的环境 2.5 激活环境&#xff0c;在当前项目目录中使用&#xff0c;即执行 python 1、需求 由于项目所依赖的 python 版本有多个&#xff0c;需要在不同的 pyth…

主从reactor多线程实现

现场模型图片&#xff0c;从网上找的 出于学习的目的实现的&#xff0c;如有不对的地方欢迎留言知道&#xff0c;简单实现了http的请求&#xff0c;可通过postman进行访问 启动项目&#xff1a; 返回数据示例 postman请求 附上源码&#xff0c;有问题直接看源码吧

智能优化算法应用:基于闪电连接过程算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于闪电连接过程算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于闪电连接过程算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.闪电连接过程算法4.实验参数设定…

Flink实时电商数仓(二)

GitLab的用户创建和推送 在root用户-密码界面重新设置密码添加Leader用户和自己使用的用户使用root用户创建相应的群组使用Leader用户创建对应的项目设置分支配置为“初始推送后完全保护”设置.gitignore文件&#xff0c;项目配置文件等其他非通用代码无需提交安装gitlab proj…

(JAVA)-创建多线程的方式

1.继承Thread类 1.创建一个继承字Thread类的子类 2.重写Thread类的run方法 public class MyThread extends Thread{Overridepublic void run() {for (int i 0; i < 100; i) {System.out.println(getName()"hello");}} }3.创建Thread类的子类对象 4.通过子类对象调…

Ubuntu:那些年踩过的坑?注意事项分享

Ubuntu系统在使用过程中可能会遇到一些需要注意的"坑"&#xff0c;以下是一些常见的问题和示例&#xff1a; 1.权限问题&#xff1a; 在Ubuntu中&#xff0c;默认情况下&#xff0c;许多系统文件和目录只有root用户才能修改。如果你试图以普通用户身份修改这些文件&a…

HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】

一.HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】 1.1 项目背景 HarmonyOS(鸿蒙操作系统)是华为公司推出的一种分布式操作系统。它被设计为一种全场景、全连接的操作系统,旨在实现在各种设备之间的无缝协同和共享,包括智能手机、平板电脑、智能…

轻量级购物小程序H5产品设计经典样例

主要是看到这个产品设计的不错值得借鉴特记录如下&#xff1a; 不过大多数购物app都大致相同&#xff0c;这个算是经典样例&#xff0c;几乎都可以复制&#xff0c;我第一次使用&#xff0c;感觉和顺畅。看上去产品是经过打磨的&#xff0c;布局非常好。内容也很丰富。支持异业…

Leetcode—128.最长连续序列【中等】

2023每日刷题&#xff08;六十四&#xff09; Leetcode—128.最长连续序列 实现代码 class Solution { public:int longestConsecutive(vector<int>& nums) {unordered_set<int> s;for(auto num: nums) {s.insert(num);}int longestNum 0;for(auto num: s) …

LeetCode day27

LeetCode day27 —今天做到树&#xff0c;&#xff0c;&#xff0c;对不起我的数据结构老师啊~~~ 7. 整数反转 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] &#xff0c…

Maven scope属性解读和使用注意事项

目录 compile runtime test system provided import dependencyManagement标签介绍 maven的scope有哪些&#xff1a; maven的scope一共包括&#xff1a;compile、runtime、test、system、provided、import。 compile <dependency><groupId>org.apache.htt…

【PostgreSQL】从零开始:(十六)数据类型-数值类型

数值类型定义 数值类型是一种用于存储数字的数据类型。在编程语言中&#xff0c;数值类型通常包括整数类型和浮点数类型。 整数类型用于存储整数值&#xff0c;包括正整数、负整数和零。在不同的编程语言中&#xff0c;整数类型可能有不同的大小限制&#xff0c;例如8位、16位…

【AI图集】猫狗的自动化合成图集

猫是一种哺乳动物&#xff0c;通常被人们作为宠物饲养。它们有柔软的毛发&#xff0c;灵活的身体和尖锐的爪子。猫是肉食性动物&#xff0c;主要以肉类为食&#xff0c;但也可以吃一些蔬菜和水果。猫通常在夜间活动&#xff0c;因此它们需要足够的玩具和活动空间来保持健康和快…

k8s pod常用资源清单

K8S 的资源清单 参数名类型字段说明apiVersionStringK8S APl 的版本&#xff0c;可以用 kubectl api versions 命令查询kindStringyam 文件定义的资源类型和角色metadataObject元数据对象&#xff0c;下面是它的属性metadata.nameString元数据对象的名字&#xff0c;比如 pod …