备忘录模式也是GOF提出的23种设计模式中行为模式的一种,大家看到这个名字可能会觉得很生疏,相信很多同学没见过这种设计模式更没有用过它,其实备忘录模式是一种非常简单容易理解的设计模式。
备忘录模式是用于哪种场景的呢?它适用于对象在执行某些操作为防止意外而在执行操作前将对象状态备份的场景,有点类似于事务回滚的意思。
下面还是先看下GOF对它的定义:
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以就该对象恢复到原先保存的状态。
备忘录模式的机构图:
备忘录模式的角色:
(1)发起人(Originator):要被备份的成员,它提供一创建备忘录的方法,其实就是将它自身的某些信息拷贝一份到一个备忘录对象中。并提供另外一个方法将备忘录中的信息覆盖自身的信息。
(2)备忘录(Memento):备忘录对象中包含存储发起人状态的成员变量,它提供set,get或构造方法保存发起人状态及获取发起人状态。
(3)管理角色(Caretaker):用于管理备忘录对象的实现类。
下面通过代码来具体实现备忘录模式。
如下为代码层次结构图:
1、第一个文件发起人角色:Game.java
点击(此处)折叠或打开
- /**
- * 游戏自身(备忘录模式中的发起人,备份的是游戏的状态)
- */
- public class Game {
- /**
- * 英雄状态属性
- */
- private HeroState hState;
- /**
- * 场景状态属性
- */
- private SceneState sState;
- public HeroState gethState() {
- return hState;
- }
- public void sethState(HeroState hState) {
- this.hState = hState;
- }
- public SceneState getsState() {
- return sState;
- }
- public void setsState(SceneState sState) {
- this.sState = sState;
- }
- /**
- * 备份游戏
- */
- public GameMemento createMemento(){
- return new GameMemento(hState,sState);
- }
- /**
- * 玩游戏
- * @throws InterruptedException
- */
- public void play(){
- hState.setHP(0);
- hState.setMP(0);
- sState.setCoin(0);
- sState.setWood(0);
- }
- /**
- * 游戏还原
- */
- public void restore(GameMemento memento){
- this.hState = memento.gethState();
- this.sState = memento.getsState();
- }
- }
2、第二个文件要备份的状态实体:HeroState.java
点击(此处)折叠或打开
- /**
- * 游戏英雄人物状态实体
- */
- public class HeroState implements Cloneable{
- /**
- * 英雄生命值
- */
- private int HP;
- /**
- * 英雄魔法值
- */
- private int MP;
- /**
- * 状态保存时间
- */
- private Date stateDate;
- public int getHP() {
- return HP;
- }
- public void setHP(int hP) {
- HP = hP;
- }
- public int getMP() {
- return MP;
- }
- public void setMP(int mP) {
- MP = mP;
- }
- public Date getStateDate() {
- return stateDate;
- }
- public void setStateDate(Date stateDate) {
- this.stateDate = stateDate;
- }
- public HeroState clone(){
- try {
- return (HeroState) super.clone();
- } catch (CloneNotSupportedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
- }
3、要备份的状态实体:SceneState.java
点击(此处)折叠或打开
- /**
- * 游戏场景状态实体
- */
- public class SceneState implements Cloneable{
- /**
- * 金币数量
- */
- private int coin;
- /**
- * 木材数量
- */
- private int wood;
- /**
- * 地图名称
- */
- private String mapName;
- public int getCoin() {
- return coin;
- }
- public void setCoin(int coin) {
- this.coin = coin;
- }
- public int getWood() {
- return wood;
- }
- public void setWood(int wood) {
- this.wood = wood;
- }
- public String getMapName() {
- return mapName;
- }
- public void setMapName(String mapName) {
- this.mapName = mapName;
- }
- public SceneState clone(){
- try {
- return (SceneState) super.clone();
- } catch (CloneNotSupportedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
- }
4、第四个文件备忘录角色:GameMemcento.java
点击(此处)折叠或打开
- /**
- * 游戏备忘录角色
- */
- public class GameMemento{
- /**
- * 英雄状态
- */
- private HeroState hState;
- /**
- * 场景状态
- */
- private SceneState sState;
- /**
- * 构造方法
- * @param hState
- * @param sState
- */
- public GameMemento(HeroState hState,SceneState sState){
- this.hState = hState.clone();
- this.sState = sState.clone();
- }
- /**
- * 获取备份状态
- * @return
- */
- public HeroState gethState() {
- return hState;
- }
- /**
- * 获取备份状态
- * @return
- */
- public SceneState getsState() {
- return sState;
- }
- }
5、第五个文件备忘录管理角色:Caretaker.java
点击(此处)折叠或打开
- /**
- * 备忘录管理器
- */
- public class Caretaker {
- /**
- * 备忘录实体
- */
- private GameMemento memento;
- public GameMemento getMemento() {
- return memento;
- }
- public void setMemento(GameMemento memento) {
- this.memento = memento;
- }
- }
6、第六个文件:TestMain.java
点击(此处)折叠或打开
- /**
- * 测试Main方法
- */
- public class TestMain {
- public static void main(String [] args){
- Game game = new Game();
- HeroState hState = new HeroState();
- hState.setHP(100);
- hState.setMP(100);
- SceneState sState = new SceneState();
- sState.setCoin(1000);
- sState.setWood(1000);
- game.sethState(hState);
- game.setsState(sState);
- System.out.println("游戏状态备份开始");
- GameMemento memento = game.createMemento();
- Caretaker ct = new Caretaker();
- ct.setMemento(memento);
- System.out.println("游戏状态备份完成");
- System.out.println("开始游戏,当前英雄生命值:" + game.gethState().getHP());
- game.play();
- System.out.println("游戏结束,当前英雄生命值:" + game.gethState().getHP());
- System.out.println("游戏状态还原开始");
- game.restore(ct.getMemento());
- System.out.println("游戏状态还原结束");
- System.out.println("当前英雄生命值:" + game.gethState().getHP());
- }
- }
很多问题看了代码自然明了,备忘录模式还是很简单的,使用非常方便。
备忘录模式的优点:
(1)将对象状态备份,便于在出现意外时进行状态回滚。
(2)对象状态的副本交由管理器(Caretaker)管理,发起人无需管理状态的备份。而在还原状态时,又由发起人自己执行状态还原方法,外界无法获取发起人的备份状态信息从而保证了备份数据的安全性。
备忘录模式的缺点:
将对象状态备份会占用较多的系统资源。