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

模版实现如下:
package com.niuh.designpattern.memento.v1; /** * <p> * 备忘录模式 * </p> */ public class MementoPattern { public static void main(String[] args) { Originator or = new Originator(); Caretaker cr = new Caretaker(); 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()); } } //备忘录 class Memento { private String state; public Memento(String state) { this.state = state; } public void setState(String state) { this.state = state; } public String getState() { return state; } } //发起人 class Originator { private String state; public void setState(String state) { this.state = state; } public String getState() { return state; } public Memento createMemento() { return new Memento(state); } public void restoreMemento(Memento m) { this.setState(m.getState()); } } //管理者 class Caretaker { private Memento memento; public void setMemento(Memento m) { memento = m; } public Memento getMemento() { return memento; } } 输出结果如下:
初始状态:S0 新的状态:S1 恢复状态:S0 解决的问题
备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,模式使数据恢复到它原先的系列状态。
每个人都有犯错误的备忘时候,都希望有种“后悔药”能弥补自己的录模过失,让自己重新开始,设计式但现实是模式残酷的。在计算机应用中,系列客户同样会常常犯错误,备忘能否提供“后悔药”给他们呢?录模当然是可以的,而且是有必要的。这个功能由“备忘录模式”来实现。
模式组成
备忘录模式的高防服务器核心是设计备忘录类以及用于管理备忘录的管理者类。

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

使用步骤
步骤1:定义备忘录角色,用于存储角色状态。
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; } 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; } } 步骤2:定义发起人角色(当前游戏角色),记录当前游戏角色的生命力、攻击力、防御力。通过saveState()方法来保存当前状态,通过recoveryState()方法来恢复角色状态。
class GameRole { private int vit; //生命力 private int atk; //攻击力 private int 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 void stateDisplay() { System.out.println("角色当前状态:"); System.out.println("体力:" + this.vit); System.out.println("攻击力:" + this.atk); System.out.println("防御力: " + this.def); System.out.println("-----------------"); } //获得初始状态 public void getInitState() { this.vit = 100; this.atk = 100; this.def = 100; } //战斗后 public void fight() { 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.getVit(); this.atk = memento.getAtk(); this.def = memento.getDef(); } } 步骤3:定义管理者角色,角色状态管理者
class RoleStateCaretaker { private RoleStateMemento memento; public RoleStateMemento getMemento() { return memento; } public void setMemento(RoleStateMemento memento) { this.memento = memento; } } 步骤4:测试输出
public class MementoPattern { // 逻辑大致为打boss前存档,打boss失败了 public static void main(String[] args) { //打boss前 GameRole gameRole = new GameRole(); gameRole.getInitState(); gameRole.stateDisplay(); //保存进度 RoleStateCaretaker caretaker = new RoleStateCaretaker(); 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 部分源码
public interface StateManageableMessageContext extends MessageContext { /** * Create a serializable memento, or token representing a snapshot of the internal state of this message context. * @return the messages memento */ public Serializable createMessagesMemento(); /** * Set the state of this context from the memento provided. After this call, the messages in this context will match * what is encapsulated inside the memento. Any previous state will be overridden. * @param messagesMemento the messages memento */ public void restoreMessages(Serializable messagesMemento); /** * Configure the message source used to resolve messages added to this context. May be set at any time to change how * coded messages are resolved. * @param messageSource the message source * @see MessageContext#addMessage(MessageResolver) */ public void setMessageSource(MessageSource messageSource); } PS:以上代码提交在 Github :
https://github.com/Niuh-Study/niuh-designpatterns.git