23种设计模式应用,设计模式系列备忘录模式(1)

作者公众号:一角钱技术(org_yijiaoqian)

前言

23种设计模式快速记忆的请看上面第一篇,本篇和大家一起来学习备忘录模式相关内容。

23种设计模式应用,设计模式系列备忘录模式(2)

模式定义

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

23种设计模式应用,设计模式系列备忘录模式(3)

模版实现如下

packagecom.niuh.designpattern.memento.v1; /** *<p> *备忘录模式 *</p> */ publicclassMementoPattern{ publicstaticvoidmain(String[]args){ Originatoror=newOriginator(); Caretakercr=newCaretaker(); or.setstate("S0"); System.out.println("初始状态:" or.getState()); cr.setMemento(or.createMemento());//保存状态 or.setState("S1"); System.out.println("新的状态:" or.getState()); or.restoreMemento(cr.getMemento());//恢复状态 System.out.println("恢复状态:" or.getState()); } } //备忘录 classMemento{ privateStringstate; publicMemento(Stringstate){ this.state=state; } publicvoidsetState(Stringstate){ this.state=state; } publicStringgetState(){ returnstate; } } //发起人 classOriginator{ privateStringstate; publicvoidsetState(Stringstate){ this.state=state; } publicStringgetState(){ returnstate; } publicMementocreateMemento(){ returnnewMemento(state); } publicvoidrestoreMemento(Mementom){ this.setState(m.getState()); } } //管理者 classCaretaker{ privateMementomemento; publicvoidsetMemento(Mementom){ memento=m; } publicMementogetMemento(){ returnmemento; } }

输出结果如下

初始状态:S0 新的状态:S1 恢复状态:S0

解决的问题

备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。

每个人都有犯错误的时候,都希望有种“后悔药”能弥补自己的过失,让自己重新开始,但现实是残酷的。在计算机应用中,客户同样会常常犯错误,能否提供“后悔药”给他们呢?当然是可以的,而且是有必要的。这个功能由“备忘录模式”来实现。

模式组成

备忘录模式的核心是设计备忘录类以及用于管理备忘录的管理者类。

23种设计模式应用,设计模式系列备忘录模式(4)

实例说明实例概况

以游戏存档为例,看一下如何用备忘录模式实现

23种设计模式应用,设计模式系列备忘录模式(5)

使用步骤

步骤1:定义备忘录角色,用于存储角色状态。

classRoleStateMemento{ privateintvit;//生命力 privateintatk;//攻击力 privateintdef;//防御力 publicRoleStateMemento(intvit,intatk,intdef){ this.vit=vit; this.atk=atk; this.def=def; } publicintgetVit(){ returnvit; } publicvoidsetVit(intvit){ this.vit=vit; } publicintgetAtk(){ returnatk; } publicvoidsetAtk(intatk){ this.atk=atk; } publicintgetDef(){ returndef; } publicvoidsetDef(intdef){ this.def=def; } }

步骤2:定义发起人角色(当前游戏角色),记录当前游戏角色的生命力、攻击力、防御力。通过saveState()方法来保存当前状态,通过recoveryState()方法来恢复角色状态。

classGameRole{ privateintvit;//生命力 privateintatk;//攻击力 privateintdef;//防御力 publicintgetVit(){ returnvit; } publicvoidsetVit(intvit){ this.vit=vit; } publicintgetAtk(){ returnatk; } publicvoidsetAtk(intatk){ this.atk=atk; } publicintgetDef(){ returndef; } publicvoidsetDef(intdef){ this.def=def; } //状态显示 publicvoidstateDisplay(){ System.out.println("角色当前状态:"); System.out.println("体力:" this.vit); System.out.println("攻击力:" this.atk); System.out.println("防御力:" this.def); System.out.println("-----------------"); } //获得初始状态 publicvoidgetInitState(){ this.vit=100; this.atk=100; this.def=100; } //战斗后 publicvoidfight(){ this.vit=0; this.atk=0; this.def=0; } //保存角色状态 publicRoleStateMementosaveState(){ return(newRoleStateMemento(vit,atk,def)); } //恢复角色状态 publicvoidrecoveryState(RoleStateMementomemento){ this.vit=memento.getVit(); this.atk=memento.getAtk(); this.def=memento.getDef(); } }

步骤3:定义管理者角色,角色状态管理者

classRoleStateCaretaker{ privateRoleStateMementomemento; publicRoleStateMementogetMemento(){ returnmemento; } publicvoidsetMemento(RoleStateMementomemento){ this.memento=memento; } }

步骤4:测试输出

publicclassMementoPattern{ //逻辑大致为打boss前存档,打boss失败了 publicstaticvoidmain(String[]args){ //打boss前 GameRolegameRole=newGameRole(); gameRole.getInitState(); gameRole.stateDisplay(); //保存进度 RoleStateCaretakercaretaker=newRoleStateCaretaker(); caretaker.setMemento(gameRole.saveState()); //打boss失败 gameRole.fight(); gameRole.stateDisplay(); //恢复状态 gameRole.recoveryState(caretaker.getMemento()); gameRole.stateDisplay(); } }

输出结果

角色当前状态: 体力:100 攻击力:100 防御力:100 ----------------- 角色当前状态: 体力:0 攻击力:0 防御力:0 ----------------- 角色当前状态: 体力:100 攻击力:100 防御力:100 -----------------

优点

备忘录模式是一种对象行为型模式,其主要优点如下。

缺点

资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。

注意事项
  1. 为了符合迪米特法则,需要有一个管理备忘录的类
  2. 不要在频繁建立备份的场景中使用备忘录模式。为了节约内存,可使用原型模式 备忘录模式
应用场景
  1. 需要保存和恢复数据的相关场景
  2. 提供一个可回滚的操作,如ctrl z、浏览器回退按钮、Backspace键等
  3. 需要监控的副本场景
模式的扩展

在备忘录模式中,有单状态备份的例子,也有多状态备份的例子。可以结合原型模式混合使用。在备忘录模式中,通过定义“备忘录”来备份“发起人”的信息,而原型模式的 clone() 方法具有自备份功能,所以,如果让发起人实现 Cloneable 接口就有备份自己的功能,这时可以删除备忘录类,其结构如下:

23种设计模式应用,设计模式系列备忘录模式(6)

源码中的应用

#Spring org.springframework.binding.message.StateManageableMessageContext

StateManageableMessageContext 部分源码

publicinterfaceStateManageableMessageContextextendsMessageContext{ /** *Createaserializablememento,ortokenrepresentingasnapshotoftheinternalstateofthismessagecontext. *@returnthemessagesmemento */ publicSerializablecreateMessagesMemento(); /** *Setthestateofthiscontextfromthemementoprovided.Afterthiscall,themessagesinthiscontextwillmatch *whatisencapsulatedinsidethememento.Anypreviousstatewillbeoverridden. *@parammessagesMementothemessagesmemento */ publicvoidrestoreMessages(SerializablemessagesMemento); /** *Configurethemessagesourceusedtoresolvemessagesaddedtothiscontext.Maybesetatanytimetochangehow *codedmessagesareresolved. *@parammessageSourcethemessagesource *@seeMessageContext#addMessage(MessageResolver) */ publicvoidsetMessageSource(MessageSourcemessageSource); }

PS:以上代码提交在 Github

https://github.com/Niuh-Study/niuh-designpatterns.git

文章持续更新,可以公众号搜一搜「 一角钱技术 」第一时间阅读, 本文 GitHub org_hejianhui/JavaStudy 已经收录,欢迎 Star。

,