JAVA设计模式之备忘录模式

一、备忘录模式简介

Memento模式也叫备忘录模式,是行为模式之一,它的作用是保存对象的内部状态,并在需要的时候(undo/rollback)恢复对象以前的状态。
如果一个对象需要保存状态并可通过undo或rollback等操作恢复到以前的状态时,可以使用Memento模式。

  • 一个类需要保存它的对象的状态(相当于Originator角色)
  • 设计一个类,该类只是用来保存上述对象的状态(相当于Memento角色)
  • 需要的时候,Caretaker角色要求Originator返回一个Memento并加以保存
  • undo或rollback操作时,通过Caretaker保存的Memento恢复Originator对象的状态

二、备忘录模式的结构

在这里插入图片描述

三、备忘录模式的角色与职责

Originator(原生者): 需要被保存状态以便恢复的那个对象。
Memento(备忘录): 该对象由Originator创建,主要用来保存Originator的内部状态。
Caretaker(管理者): 负责在适当的时间保存/恢复Originator对象的状态。

四、备忘录模式的具体实现

超级玛丽奥的游戏推出了新版本,可以在中途保存游戏进度,以便下次继续。
首先我们定义一个接口,用来在游戏中定义存档。

// An highlighted block
package design.memo.gys.memo;
public interface MemoInfo {
}

所有需要存档的游戏都需要实现该接口,并且将备忘录类私有化成游戏内部。
超级马里奥1是Jim开发的,他使用Hashmap来保存游戏的状态,因此,备忘录必须匹配该游戏状态。

// An highlighted block
package design.memo.gys.memo;
import java.util.HashMap;
public class GameA {
 private HashMap<String, String> state;
 public GameA() {
  state=new HashMap<>();
 }
 public MemoInfo creatMemo() {
  return new Memoto(state);
 }
 public void reStoreMemo(MemoInfo memoinfo) {
  this.state=((Memoto)memoinfo).getState();
 }
 public void showState() {
  System.out.println("Current state:"+state.toString());
 }
 public void test1() {
  state=new HashMap<>();
  state.put("Gate", "3");
  state.put("blood", "500");
  state.put("Enemy", "5");
 }
 public void test2() {
  state=new HashMap<>();
  state.put("Gate", "4");
  state.put("blood", "1");
  state.put("Enemy", "3");
 }
 private class Memoto implements MemoInfo{
  private HashMap<String, String> state;
  public Memoto(HashMap<String, String> state) {
   super();
   this.state = new HashMap(state);
  }
  public HashMap<String,String> getState(){
   return state;
  }
  public void setState(HashMap state) {
   this.state=state;
  }
 }
}

该程序内部提供了一个状态显示函数并且给出了两个测试函数,可以看到,在private的Memoto类中,该类的构造器使用的是

// An highlighted block
public Memoto(HashMap<String, String> state) {
   super();
   this.state = new HashMap(state);
  }

代码中重新创建了新的Hashmap,并将原来的状态作为参数传入,如果不这样做,得到的知识原来状态的新的引用,无法作为备忘录进行存储并恢复。
超级马里奥2是由Jhon来制作完成的,在这个游戏中,使用的是ArrayList来显示状态,其余的工作和1中是一样的:

// An highlighted block
package design.memo.gys.memo;
import java.util.ArrayList;
public class GameB {
 private ArrayList<String> state;
 public GameB() {
  state=new ArrayList<>();
 }
 public MemoInfo creatMemo() {
  return new Memoto(state);
 }
 public void reStoreMemo(MemoInfo memoinfo) {
  this.state=((Memoto)memoinfo).getState();
 }
 public void showState() {
  System.out.println("Current state:"+state.toString());
 }
 public void test1() {
  state=new ArrayList<>();
  state.add("Level:4");
  state.add("blood:100");
  state.add("Enemy:4");
 }
 public void test2() {
  state=new ArrayList<>();
  state.add("Level:5");
  state.add("blood:2");
  state.add("Enemy:6");
 }
 private class Memoto implements MemoInfo{
  private ArrayList<String> state;
  public Memoto(ArrayList<String> state) {
   super();
   this.state = new ArrayList<>(state);
  }
  public ArrayList<String> getState(){
   return state;
  }
  public void setState(ArrayList<String> state) {
   this.state=state;
  }
 }
}

在这两个游戏中,都有产生备忘录以及获取状态的函数,现在,我们需要一个存档,将其进行保存。

// An highlighted block
package design.memo.gys.memo;
import java.util.HashMap;
public class Crack {
 private HashMap<String, MemoInfo> crack;
 public Crack() {
  crack=new HashMap<>();
 }
 public void addMemo(String name,MemoInfo memo) {
  crack.put(name,memo);
  System.out.println("保存游戏进度...");
 }
 public MemoInfo getMemo(String name) {
  System.out.println("恢复游戏进度...");
  return crack.get(name);
 }
}

在这个存档中可以保存所有马里奥系列的进度,并且能够读取各自的进度而不互相干扰。

// An highlighted block
package design.memo.gys.memo;
public class Test {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  Crack load=new Crack();
  GameA g1=new GameA();
  g1.test1();
  g1.showState();
  load.addMemo("GameA", g1.creatMemo());
  g1.test2();
  g1.showState();
  g1.reStoreMemo(load.getMemo("GameA"));
  g1.showState();
  System.out.println("-----------");
  GameB g2=new GameB();
  g2.test1();
  g2.showState();
  load.addMemo("GameB", g2.creatMemo());
  g2.test2();
  g2.showState();
  g2.reStoreMemo(load.getMemo("GameB"));
  g2.showState();
  System.out.println("-----------");
  try {
  g2.reStoreMemo(load.getMemo("GameA"));}
  catch(ClassCastException e) {
   System.out.println("记录类型不匹配!!!!");
  }
 }
}

看一下测试结果吧。

// An highlighted block
Current state:{Enemy=5, Gate=3, blood=500}
保存游戏进度...
Current state:{Enemy=3, Gate=4, blood=1}
恢复游戏进度...
Current state:{Gate=3, blood=500, Enemy=5}
-----------
Current state:[Level:4, blood:100, Enemy:4]
保存游戏进度...
Current state:[Level:5, blood:2, Enemy:6]
恢复游戏进度...
Current state:[Level:4, blood:100, Enemy:4]
-----------
恢复游戏进度...
记录类型不匹配!!!!

可以看到,两次都顺利的恢复了各自的游戏进度,但是在A尝试读取B的进度时出现了错误,也就是说A无法解析B的内部状态,使用private内部类很好的隐藏了内部的实现细节。

五、备忘录模式的优缺点

优点:

  1. 状态存储在外面,不和关键对象混在一起,帮助内聚
  2. 提供容易实现的状态恢复能力
  3. 保持了关键对象的封装

缺点:

  1. 资源消耗较大
  2. 存储和恢复状态的过程比较复杂

要抱抱才会开心啊~~~~~~~~~~~~

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值