首页 > 编程语言 >【Java设计模式】二十二、备忘录模式

【Java设计模式】二十二、备忘录模式

时间:2024-03-16 18:00:46浏览次数:26  
标签:二十二 Java int void atk vit 设计模式 public def

文章目录

1、备忘录模式

一种状态恢复机制,以便可以回到之前的某一个特定状态。如Word的撤销操作、下棋时的悔棋等。

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

主要角色有:

  • 发起人角色:记录当前时刻的内部状态信息,包含创建备忘录 + 恢复备忘录数据的方法
  • 备忘录角色:发起人状态的一个备份,负责存储发起人的内部状态,并能提供内部状态数据给发起人去恢复数据
  • 管理者角色:管理备份,包含保存备忘录 + 获取备忘录的方法

2、案例:游戏角色属性数值恢复

一游戏角色有生命力、攻击力、防御力三个数值,而打Boss会掉血,现要支持可恢复到打Boss前的状态。

2.1 白箱备忘录模式

即备忘录角色内部所存储的状态,对所有对象公开。

在这里插入图片描述

先定义发起人角色:游戏角色类(它需要备份和恢复),注意saveState和recoverState方法

//游戏角色类
@Getter
@Setter
public class GameRole {

    private int vit; //生命力
    private int atk; //攻击力
    private int def; //防御力

    //初始化状态,默认出门给100生命值
    public void initState() {
        this.vit = 100;
        this.atk = 100;
        this.def = 100;
    }

    //战斗,让生命值为0,模拟残血
    public void fight() {
        this.vit = 0;
        this.atk = 0;
        this.def = 0;
    }

    //保存角色状态,即创建备份者对象,并将发起者的属性值存入
    public RoleStateMemento saveState() {
        return new RoleStateMemento(vit, atk, def);
    }

    //恢复角色状态,即从备份者对象中取出属性,给当前发起者对象赋值
    public void recoverState(RoleStateMemento roleStateMemento) {
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }

	//业务方法,展示下当前发起者的属性,方便看测试效果
    public void stateDisplay() {
        System.out.println("角色生命力:" + vit);
        System.out.println("角色攻击力:" + atk);
        System.out.println("角色防御力:" + def);
    }
}

定义备忘者类:

//游戏状态存储类(备忘录类)
@Getter
@Setter
public class RoleStateMemento {

    private int vit;
    private int atk;
    private int def;

    public RoleStateMemento(int vit, int atk, int def) {
        this.vit = vit;
        this.atk = atk;
        this.def = def;
    }
   
}

定义管理者类,保存和给外界获取备忘录对象。这里直接用get和set方法搭配一个属性简单地完成一下存储和获取。如果对象很多,可使用Map<String, 备忘录类>

//角色状态管理者类
public class RoleStateCaretaker {
    private RoleStateMemento roleStateMemento;

    public RoleStateMemento getRoleStateMemento() {
        return roleStateMemento;
    }

    public void setRoleStateMemento(RoleStateMemento roleStateMemento) {
        this.roleStateMemento = roleStateMemento;
    }
}

测试类,看下效果:

//测试类
public class Client {
    public static void main(String[] args) {
        System.out.println("------------大战Boss前------------");
        //大战Boss前
        GameRole gameRole = new GameRole();
        gameRole.initState();   //初始化生命值等,给100
        gameRole.stateDisplay();  //打印生命值等属性

        //保存进度
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();  //创建管理者对象
        roleStateCaretaker.setRoleStateMemento(gameRole.saveState());  //保存备份者对象到管理者

        System.out.println("------------大战Boss后------------");
        //大战Boss时,损耗严重
        gameRole.fight();
        gameRole.stateDisplay();
        System.out.println("------------恢复之前状态------------");
        //恢复之前状态
        gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());   //从管理者获取到备份对象,给发起者去恢复
        gameRole.stateDisplay();

    }
}

运行:

在这里插入图片描述

以上:在管理者类中,可以修改备忘录对象的值,这也是白箱模式的问题所在。

在这里插入图片描述

2.2 黑箱备忘录模式

以上的问题,我希望:备忘录角色对象,对发起人对象是宽接口,而对管理者对象、其他对象是窄接口(权限和功能有限)。

Java中,实现双重接口(宽、窄接口)的方式是设计成内部成员类。

因此,将备忘录类设计成发起人类的内部成员类:

在这里插入图片描述

定义备忘录的窄接口Memento,这是一个标识接口,因此没有定义出任何的方法

public interface Memento {
}

定义发起人类 GameRole,并在内部定义备忘录内部类 RoleStateMemento去实现Memento(该内部类设置为私有的),注意saveState和recoverState方法的形参类型面向接口,直接调用没有任何方法,需要向下转型为私有的内部类

//游戏角色类
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 = 0;
        this.def = 0;
    }

    //保存角色状态
    public Memento saveState() {
        return new RoleStateMemento(vit, atk, def);
    }

    //恢复角色状态
    public void recoverState(Memento memento) {
    	向下转型
        RoleStateMemento roleStateMemento = (RoleStateMemento) memento;  
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }
	
	//业务方法,展示下当前发起者的属性,方便看测试效果
    public void stateDisplay() {
        System.out.println("角色生命力:" + vit);
        System.out.println("角色攻击力:" + atk);
        System.out.println("角色防御力:" + def);

    }

	//Getter 和 Setter
    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(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;
        }
    }
}

负责人角色类 RoleStateCaretaker 能够得到的备忘录对象是以 Memento 为接口的,由于这个接口仅仅是一个标识接口,因此负责人角色不可能改变这个备忘录对象的内容(因为无任何方法可调)

//角色状态管理者类
public class RoleStateCaretaker {
    private Memento memento;   //这次用Memento类型的备份者对象

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

客户端测试类:

public class Client {
    public static void main(String[] args) {
        System.out.println("------------大战Boss前------------");
        //大战Boss前
        GameRole gameRole = new GameRole();
        gameRole.initState();
        gameRole.stateDisplay();

        //保存进度
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();   //创建管理者对象
        roleStateCaretaker.setMemento(gameRole.saveState());   //保存备份对象到管理者
        
        System.out.println("------------大战Boss后------------");
        //大战Boss时,损耗严重
        gameRole.fight();
        gameRole.stateDisplay();
        System.out.println("------------恢复之前状态------------");
        //恢复之前状态
        gameRole.recoverState(roleStateCaretaker.getMemento());
        gameRole.stateDisplay();
    }
}

到此,管理者对象就不能去修改或者访问我的备份者对象的属性数据了。 因为管理者对象里是Memento类,而Memento中无任何方法。这就是黑箱!

在这里插入图片描述

最后,一句话,白箱变黑箱,是把备忘录的类定义在了发起者的内部,且为private,只允许本类访问。

3、总结

优点:

  • 提供了状态恢复机制来恢复对象数据
  • 黑箱模式下,除了发起人,其他对象均不可更改或者访问备份对象的信息
  • 简化了发起人角色类,它自己不需要去保存其内部各个状态的备份,而是信息存备忘录对象后,交给管理者对象统一管理

缺点:

  • 很明显,如果保存状态很多,则管理者类存储的备份者对象就很多,会占用大量内存

适用场景:

  • 需要保存和恢复中间数据,如游戏中间数据的临时存档
  • 需要提供一个可回滚的场景时,如撤销

标签:二十二,Java,int,void,atk,vit,设计模式,public,def
From: https://blog.csdn.net/llg___/article/details/136660951

相关文章

  • 【Java】SpringMVC
    MVC是模型(Mode)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。将业务逻辑和数据显示分离,降低了视图与业务逻辑间的双向耦合。DaoServiceServletjsp/html①用户发送请求②Servlet接收请求数据,调用对应的业务逻辑方法③业务处理完毕,返回更新后的数据给servlet④......
  • (java毕业设计源码)基于java(springboot)校园求职招聘系统
    基于java(springboot)校园求职招聘系统项目获取请看文章最底下官网校园求职招聘管理系统,是基于java编程语言,mysql数据库,springboot+vue框架进行开发,本系统分为学生,企业,管理员三个角色,本系统适合作为java毕业设计和java课程设计源码下载进行参考学习。一.技术环境JDK......
  • 【Java】迷你DVD管理器
    Java:迷你DVD管理器系统概述开发计划系统开发步骤编码顺序界面交互设计的原则理解业务设计阶段1、初始化DVD信息2、实现菜单切换3、实现查看DVD信息4、实现新增DVD信息5、实现删除DVD信息6、实现借出DVD业务处理7、实现归还DVD业务处理代码阶段1、菜单模块2、初始化模......
  • JavaScript操作函数
    JavaScript操作函数通过标签事件触发函数(js),在函数中又返回来对网页中的标签操作在js中如何能够操作网页中的标签在js语言中,认为每一个标签就是一个独一无二的对象,在js语言中可以获得网页中的标签,这样就可以在js中对标签的属性,内容,样式及逆行操作要操作哪个标签,首先......
  • Java基础面试题整理2024/3/13
    1、可以使用switch的数据类型Java5以前,switch(arg)表达式中,arg只能是byte、short、char、int。Java5之后引入了枚举类型,也可以是枚举类型。Java7开始引入了字符串类型。2、Java中的goto有什么作用goto是Java中的保留字,在目前版本的Java中没有使用。3、this与super的区......
  • 基于Java+SpringBoot的开放实验室管理系统子系统毕业设计(源码+论文)
    作者主页:Java程序员老张主要内容:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。收藏点赞不迷路 关注作者有好处文末获取源码技术选型【后端】:Java【框架】:SpringBoot【前端】:vue【JDK版本】:JDK1.8【服......
  • java企业员工档案管理(ssm框架毕业设计)
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义在现代企业管理中,员工档案管理是一个重要的组成部分。它不仅涉及到员工的个人信息,还包含了他们的工作经历、技能培训、绩效评估等重要内容。因此,如何有效地管理这......
  • java企业员工岗前培训管理系统(ssm框架毕业设计)
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:在当今激烈的市场竞争环境下,企业对员工的要求越来越高,员工的专业能力和综合素质直接影响到企业的生产力和竞争力。然而,新入职的员工往往需要一段时间来适......
  • Java两周半速成之路(第十六天)
    一、网络编程1.概述:         就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换2.网络模型 3.网络参考模型图  4.网络通信三要素 4.1IP地址 InetAddress类的使用:注意:通过API查看,此类没有构造方法,如果想要创建该类的对象,......
  • JavaScript 数据驼峰结构转下划线结构
    //数据转换functionrecursionFunc(data){if(data&&typeof(data)=='object'){varobjif(Array.isArray(data)){obj=[]for(varitemofdata){obj.push(recursionFunc(item))}}else{......