作者公众号:一角钱技术(org_yijiaoqian)
前言- 23种设计模式速记
- 单例(singleton)模式
- 工厂方法(factory method)模式
- 抽象工厂(abstract factory)模式
- 建造者/构建器(builder)模式
- 原型(prototype)模式
- 享元(flyweight)模式
- 外观(facade)模式
- 适配器(adapter)模式
- 装饰(decorator)模式
- 观察者(observer)模式
- 策略(strategy)模式
- 桥接(bridge)模式
- 模版方法(template method)模式
- 责任链(chain of responsibility)模式
- 组合(composite)模式
- 代理(proxy)模式
- 持续更新中......
23种设计模式快速记忆的请看上面第一篇,本篇和大家一起来学习备忘录模式相关内容。
模式定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。
模版实现如下:
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
备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。
每个人都有犯错误的时候,都希望有种“后悔药”能弥补自己的过失,让自己重新开始,但现实是残酷的。在计算机应用中,客户同样会常常犯错误,能否提供“后悔药”给他们呢?当然是可以的,而且是有必要的。这个功能由“备忘录模式”来实现。
模式组成备忘录模式的核心是设计备忘录类以及用于管理备忘录的管理者类。
实例说明实例概况
以游戏存档为例,看一下如何用备忘录模式实现
使用步骤
步骤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
-----------------
备忘录模式是一种对象行为型模式,其主要优点如下。
- 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
- 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
- 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
注意事项- 为了符合迪米特法则,需要有一个管理备忘录的类
- 不要在频繁建立备份的场景中使用备忘录模式。为了节约内存,可使用原型模式 备忘录模式
- 需要保存和恢复数据的相关场景
- 提供一个可回滚的操作,如ctrl z、浏览器回退按钮、Backspace键等
- 需要监控的副本场景
在备忘录模式中,有单状态备份的例子,也有多状态备份的例子。可以结合原型模式混合使用。在备忘录模式中,通过定义“备忘录”来备份“发起人”的信息,而原型模式的 clone() 方法具有自备份功能,所以,如果让发起人实现 Cloneable 接口就有备份自己的功能,这时可以删除备忘录类,其结构如下:
源码中的应用
#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。
,