在讲述这个模式之前,我们先看一个案例:游戏回档
游戏的某个场景,一游戏角色有生命力、攻击力、防御力等数据,在打Boss前和后会不一样,我们允许玩家如果感觉与Boss决斗的效果不理想,可以让游戏恢复到决斗前。下面是代码:
游戏角色类,用来存储角色的生命力、攻击力、防御力的数据。
public class GameRole { private int vit;//生命力 private int atk;//攻击力 private int def;//防御力 //状态显示 public void stateDisplay() { System.out.println("当前角色状态:"); System.out.println("体力:"+this.vit); System.out.println("攻击力"+this.atk); System.out.println("防御力"+this.def); } //获取初始状态 public void getInitState() { //数据通常来自本地磁盘或远程数据库 this.vit = 100; this.atk = 100; this.def = 100; } //战斗 public void fight() { //在与Boss大战后游戏数据损耗为0 this.vit = 0; this.atk = 0; this.def = 0; } //省略getter、setter方法 } //测试方法 public class Test { public static void main(String[] args) { //大战Boss前 GameRole lixiaoyao = new GameRole(); lixiaoyao.getInitState();//Boss大战前,获得角色初始状态 lixiaoyao.stateDisplay(); //保存进度,通过游戏角色的新实例来保存进度 GameRole backup = new GameRole(); backup.setVit(lixiaoyao.getVit()); backup.setAtk(lixiaoyao.getAtk()); backup.setDef(lixiaoyao.getDef()); //大战Boss时,损耗严重,所有数据全部损耗为0 lixiaoyao.fight(); lixiaoyao.stateDisplay(); //恢复之前状态,重新来玩 lixiaoyao.setVit(backup.getVit()); lixiaoyao.setAtk(backup.getAtk()); lixiaoyao.setDef(backup.getDef()); lixiaoyao.stateDisplay(); } }
上面的代码实现了效果,但是不理想的是:main方法里暴露了太多“细节”,使得main方法需要知道“生命力、攻击力、防御力”这样的细节。以后需要增加“魔法值”或修改现有的“生命力”为“经验值”,这部分就要修改了。同样的道理也存在于恢复时的代码。显然,我们希望的是把这些“游戏角色”的存取状态细节封装起来,而且最好是封装在外部的类中。以体现职责分离。
下面介绍备忘录模式: http://www.runoob.com/design-pattern/memento-pattern.html
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。
用备忘录模式优化案例
public class GameRole { private int vit;//生命力 private int atk;//攻击力 private int def;//防御力 //状态显示 public void stateDisplay() { System.out.println("当前角色状态:"); System.out.println("体力:"+this.vit); System.out.println("攻击力"+this.atk); System.out.println("防御力"+this.def); } //获取初始状态 public void getInitState() { //数据通常来自本地磁盘或远程数据库 this.vit = 100; this.atk = 100; this.def = 100; } //战斗 public void fight() { //在与Boss大战后游戏数据损耗为0 this.vit = 0; this.atk = 0; this.def = 0; } //新增“保存角色状态”方法,将游戏角色的三个状态值通过实例化“角色状态存储箱”返回 public RoleStateMemento saveState() { return new RoleStateMemento(vit, atk, def); } //新增“恢复角色状态”方法,可将外部的“角色状态存储箱”中的状态值恢复给游戏角色 public void recoveryState(RoleStateMemento memento) { this.vit = memento.getAtk(); this.atk = memento.getAtk(); this.def = memento.getDef(); } //省略getter、setter方法 } //角色状态存储箱类 public class RoleStateMemento { private int vit;//生命力 private int atk;//攻击力 private int def;//防御力 //将生命力、攻击力、防御力存入状态存储箱对象中 public RoleStateMemento(int vit, int atk, int def) { super(); this.vit = vit; this.atk = atk; this.def = def; } //省略getter、setter方法 } //角色状态管理者类 public class RoleStateCaretaker { private RoleStateMemento memento; public RoleStateMemento getMemento() { return memento; } public void setMemento(RoleStateMemento memento) { this.memento = memento; } } //测试方法 public class Test { public static void main(String[] args) { //大战Boss前 GameRole lixiaoyao = new GameRole(); lixiaoyao.getInitState();//Boss大战前,获得角色初始状态 lixiaoyao.stateDisplay(); //保存进度,由于封装在Memento中,因此我们并不知道保存了哪些具体的数据 RoleStateCaretaker stateAdmin = new RoleStateCaretaker(); stateAdmin.setMemento(lixiaoyao.saveState()); //大战Boss时,损耗严重 lixiaoyao.fight(); lixiaoyao.stateDisplay(); //恢复之前的状态 lixiaoyao.recoveryState(stateAdmin.getMemento()); lixiaoyao.stateDisplay(); } }
输出结果同上。
肯定有人会问:对于“角色状态”的保存,直接调用RoleStateMemento进行set和get不就行了,为什么还需要一个RoleStateCaretaker类呢?
这是为了符合 迪米特法 则进行的优化!
备忘录模式也是有缺点的,角色状态需要完整存储到备忘录对象中,如果状态数据很大很多,那么在资源消耗上,备忘录对象会非常耗内存。所以也不是用的越多越好。
以上就是实例讲解JAVA设计模式之备忘录模式的详细内容,更多关于JAVA 备忘录模式的资料请关注我们其它相关文章!
时间:2020-06-24
Memento定义:memento是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态. Memento模式相对也比较好理解,我们看下列代码: 复制代码 代码如下: public class Originator { private int number; private File file = null; public Originator(){} // 创建一个Memento public Memento getMemento(){ return new Me
本文实例讲述了JAVA设计模式之备忘录模式.分享给大家供大家参考,具体如下: 备忘录模式:又叫做快照模式,指在不破坏封装性的前提下,获取到一个对象的内部状态,并在对象之外记录或保存这个状态.在有需要的时候可将该对象恢复到原先保存的状态.我们相当于把对象原始状备份保留,所以叫备忘录模式. *模式 角色对象组成: 1.发起者对象:负责创建一个备忘录来记录当前对象的内部状态,并可使用备忘录恢复内部状态. 2.备忘录对象:负责存储发起者对象的内部状态,并防止其他对象访问备忘录. 3.管理者对象:负责备忘
23种设计模式第十八篇:java备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样就可以将该对象恢复到原先保存的状态. 类型:行为类 类图: 我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态.比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回.这时我们便可以使用备忘录模式来实现. 备忘录模式的结构 发起人:记录当前时刻的内部状态
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样就可以将该对象恢复到原先保存的状态 类型:行为类 类图: 我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态.比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回.这时我们便可以使用备忘录模式来实现. 备忘录模式的结构 发起人:记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和
定义:提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节. 类型:行为类模式 类图: 如果要问Java中使用最多的一种模式,答案不是单例模式,也不是工厂模式,更不是策略模式,而是迭代器模式,先来看一段代码吧: public static void print(Collection coll){ Iterator it = coll.iterator(); while(it.hasNext()){ String str = (String)it.next(); System.out
定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子. 类型:行为类模式 类图: 解释器模式是一个比较少用的模式,本人之前也没有用过这个模式.下面我们就来一起看一下解释器模式. 解释器模式的结构 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作.具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器Nonterm
定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 类图: 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过的行为类模式中,有一种模式也是关注对算法的封装--模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装类Context,它与模版方法模式的区别在于:在模版方法模式中,调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是封装到了封装类Context中
引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其
定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 类型:行为类模式 类图: 命令模式的结构 顾名思义,命令模式就是对命令的封装,首先来看一下命令模式类图中的基本结构: Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令. ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现. Client类:最终的客户端调用类.
定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 类型:创建类模式 类图: 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype.Prototype类需要具备以下两个条件: 实现Cloneable接口.在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法.在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedExcepti
Java异常类层次结构图: 异常的英文单词是exception,字面翻译就是"意外.例外"的意思,也就是非正常情况.事实上,异常本质上是程序上的错误,包括程序逻辑错误和系统错误.比如使用空的引用.数组下标越界.内存溢出错误等,这些都是意外的情况,背离我们程序本身的意图.错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误,在编译期间出现的错误有编译器帮助我们一起修正,然而运行期间的错误便不是编译器力所能及了,并且运行期间的错误往往是难以预料的.假若程序在运行期间出现了错误
Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使用final关键字的实例.final经常和static一起使用来声明常量,你也会看到final是如何改善应用性能的. final关键字的含义? final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如
Date类 在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理.这里简单介绍一下Date类的使用. 1.使用Date类代表当前系统时间 Date d = new Date(); System.out.println(d); 使用Date类的默认构造方法创建出的对象就代表当前时间,由于Date类覆盖了toString方法,所以可以直接输出Date类型的对象,显示的结果如下: Sun Ma