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

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

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

备忘录模式

定义

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

结构

  • 发起人角色(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,一经查实,立即删除!

相关文章

Java 自定义注解

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

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

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

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

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

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

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

主从reactor多线程实现

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

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

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

Flink实时电商数仓(二)

GitLab的用户创建和推送 在root用户-密码界面重新设置密码添加Leader用户和自己使用的用户使用root用户创建相应的群组使用Leader用户创建对应的项目设置分支配置为“初始推送后完全保护”设置.gitignore文件,项目配置文件等其他非通用代码无需提交安装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.通过子类对象调…

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…

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

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

Golang(壹)

爱情不需要华丽的言语&#xff0c;只需要默默的行动。 简介 应用领域&#xff1a; 下载vscode 使用vscode Go下载 - Go语言中文网 - Golang中文社区 下载sdk 解压到文件中&#xff0c;打开sdk解压文件 穿插dos操作系统知识点&#xff1a; 测试go语言环境 看到vscode 的目录结…

SpringIOC之AnnotatedElementKey

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Unity学习笔记(零基础到就业)|Chapter01:C#入门

Unity学习笔记&#xff08;零基础到就业&#xff09;&#xff5c;Chapter01:C#入门 前言一、控制台输入输出语句二、初识变量1.一些好用的tips2.变量声明的固定写法3.变量类型 三、变量的本质1.变量的存储空间2.变量的本质&#xff1a;2进制 四、变量的命名规范1.必须遵守的规则…

centos开机自启动实战小案例

1.编写一个我们需要做事的脚本 #!/bin/bash # 打印 "Hello" echo "Hello,Mr.Phor" # 为了更好的能看到效果 我们把这段文本放置到一个文件中 如果重启能够看到 /a.txt文件 我们实验成功 echo "hahahahahahahaha" > /a.txt #每次开机 执行…

《空气质量持续改善行动计划》发布,汉威科技助力蓝天保卫战

近日&#xff0c;国务院印发《空气质量持续改善行动计划》&#xff0c;这是继2013年“大气十条”之后的第三个国家层面的保卫蓝天行动计划。 计划要求协同推进降碳、减污、扩绿、增长&#xff0c;以改善空气质量为核心&#xff0c;以减少重污染天气和解决人民群众身边的突出大…

保护您的Android应用程序:Android应用程序安全一览

保护您的Android应用程序&#xff1a;Android应用程序安全一览 我们都知道Android是为所有人设计的——开放、面向开发者、面向用户&#xff0c;这种开放性为今天和明天的移动技术提供了很多便利。然而&#xff0c;开放性也带来了需要妥善处理的安全风险。 安全是我们所有人都…

WPF仿网易云搭建笔记(7):HandyControl重构

文章目录 专栏和Gitee仓库前言相关文章 新建项目项目环境项目结构 代码结果结尾 专栏和Gitee仓库 WPF仿网易云 Gitee仓库 WPF仿网易云 CSDN博客专栏 前言 最近我发现Material Design UI的功能比较简单&#xff0c;想实现一些比较简单的功能&#xff0c;比如消息提示&#xff0…