设计模式之备忘录模式

一、定义

   这个模式就是保存某个对象某个时刻的状态,并且通过某种方式能够使对象恢复到这个时刻的状态。

二、实例

假如你要到某个小镇,在路上你遇到个三叉路口,你不知道应该选择哪一个,因此你必须一个一个去尝试直到到达小镇。每一次尝试一条路之后,如果行不通你都要返回到三岔路口,尝试下一条路。这时候你就需要备忘录模式,记下这个三叉路口的位置。
首先定义一个walker,其中的state代表他此时的状态是回到了岔口还是尝试一条路。
public class Walker {
 private String state = null ;

 public String getState() {
  return state;
 }

 public void setState(String state) {
  this.state = state;
 }
 public MemoRandum restoreMemo() {
  return new MemoRandum(this.state);
 }
 public void backupMemo(MemoRandum memoRandum) {
  this.state = memoRandum.getState();
 }
}
    然后有一个备忘录类:
public class MemoRandum {
 private String state = null ;

 public MemoRandum(String state) {
  this.state = state;
 }

 public String getState() {
  return state;
 }
 public void setState(String state) {
  this.state = state;
 }

}
    一个备忘录的管理类,负责备忘录的创建和记录    
public class MemoManager {
 private MemoRandum memoRandum = null ;

 public MemoManager(MemoRandum memoRandum) {
  this.memoRandum = memoRandum;
 }
 public MemoRandum getMemoRandum() {
  return memoRandum;
 }
 public void setMemoRandum(MemoRandum memoRandum) {
  this.memoRandum = memoRandum;
 }

}
 测试代码
Walker xiaoming = new Walker();
  xiaoming.setState("停在岔路口");
  System.out.println("========xiaoming的此时的状态=======");
  System.out.println(xiaoming.getState());
  System.out.println("========xiaoming保存状态之后=======");
  MemoManager memoManager = new MemoManager(xiaoming.restoreMemo());
  xiaoming.setState("尝试一个路口");
  System.out.println(xiaoming.getState());
  System.out.println("========xiaoming回复之前的状态======");
  xiaoming.backupMemo(memoManager.getMemoRandum());
  System.out.println(xiaoming.getState());
结果:
========xiaoming的此时的状态=======
停在岔路口
========xiaoming保存状态之后=======
尝试一个路口
========xiaoming回复之前的状态======
停在岔路口
   在这个例子中,就是很简单的将walker类的一个变量在改变之前先存放到另外一个类里面,而这个存放的过程是用一个专门的类完成的。实际上,管理类的存在对于上层模块来说并不重要,我想要给walker备份的时候,不一定要通过一个专门的类,通过walker自身也是可以的。
    上面的walker改成如下。其实只是把对备忘录的定义和记录放在了walker类里面而已。
public class Walker2 {
 private MemoRandum memoRandum = null ;
 private String state = null ;
 public MemoRandum getMemoRandum() {
  return memoRandum;
 }
 public void setMemoRandum(MemoRandum memoRandum) {
  this.memoRandum = memoRandum;
 }
 public String getState() {
  return state;
 }
 public void setState(String state) {
  this.state = state;
 }
 public void createMemo() {
  this.setMemoRandum(new MemoRandum(this.state));
 }
 public void backupMemo() {
  this.setState(this.getMemoRandum().getState());
 }

}
测试代码:
Walker2 xiaoming2 = new Walker2();
  xiaoming2.setState("停在岔路口");
  System.out.println("========xiaoming2的此时的状态=======");
  System.out.println(xiaoming2.getState());
  System.out.println("========xiaoming2保存状态之后=======");
  xiaoming2.createMemo();
  xiaoming2.setState("尝试一个路口");
  System.out.println(xiaoming2.getState());
  System.out.println("========xiaoming2回复之前的状态======");
  xiaoming2.backupMemo();
  System.out.println(xiaoming2.getState());
结果:
========xiaoming2的此时的状态=======
停在岔路口
========xiaoming2保存状态之后=======
尝试一个路口
========xiaoming2回复之前的状态======
停在岔路口

三、扩展

    看完上面的例子,你肯定会说上面的walker只有一个属性,那如果属性很多怎么办呢,一个一个去set吗?不,当然有好的方法!我们玩闯关类游戏的时候都用过存档功能,在过一个很难的关之前先备份一下可以为自己以后省去很多麻烦。那我们就用备忘录模式来实现一下。
    首先先定义一个游戏的角色类。其中createMemo和backupMemo函数负责保存和恢复,BeanUtil类是我们自己写的,接下来会说到。
public class GameRole {
 private String name = null ;
 private int enegy = 0;
 private int blood = 0;
 private MemoRandum2 memoRandum2 = new MemoRandum2() ;
 public GameRole(String name,int enegy,int blood) {
  this.name = name ;
  this.enegy = enegy;
  this.blood = blood;
 }
 public void createMemo() {
  this.memoRandum2.setPros(BeanUtil.getHashMap(this));
 }
 public void backupMemo() {
  BeanUtil.setHashMap(this.memoRandum2.getPros(), this);
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getEnegy() {
  return enegy;
 }
 public void setEnegy(int enegy) {
  this.enegy = enegy;
 }
 public int getBlood() {
  return blood;
 }
 public void setBlood(int blood) {
  this.blood = blood;
 }
 public void print() {
  System.out.println("name:"+this.name+" blood:"+this.blood+" enegy:"+this.enegy);
 }
}
由于备份的数据多起来了,备忘录的类也要改变一下,我们用一个HashMap类型来存变量。
public class MemoRandum2 {

 private HashMap<String, Object> pros = new HashMap<String, Object>();
 public HashMap<String, Object> getPros() {
  return pros;
 }
 public void setPros(HashMap<String, Object> pros) {
  this.pros = pros;
 }

}
接下来说一下BeanUtil类(很重要),这个类负责将一个类里面的属性放到HashMap里面或者将HashMap里面的属性放到一个类里面。(注意看代码中的注解)
public class BeanUtil {
 /*
  * 功能:将一个类里面的参数放到HashMap里面并返回这个HashMap
  * 参数object:属性值得来源类,这个函数就是从object中去取属性
  */
 public static HashMap<String, Object> getHashMap(Object object) {
  HashMap<String, Object> result = new HashMap<String, Object>();//先定义一个HashMap
  try {
   BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());//取对object类的描述
   //取object类里面所有属性的描述, beanInfo.getPropertyDescriptors()返回的是一个数组,这个数组里面的每一个元素都是一个对object中属性的描述类。
   PropertyDescriptor[] pros = beanInfo.getPropertyDescriptors();
   //遍历每一个属性
   for (PropertyDescriptor des : pros) {
    //取属性名
    String name = des.getName();
    //如果某个属性的类别不是普通变量而是一个对象的话,它的名称就是class
    if(name.equals("class")){
     continue;
    }
    //取属性的读取方法并执行
    Method method = des.getReadMethod();
    //invoke就是执行这个方法,执行object中的method对应的方法并将返回值赋值给value
    //这个里面的new Object[]{}这个似乎没什么用啊
    Object value = method.invoke(object, new Object[]{});
    result.put(name, value);
   }
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return result;
 }
 public static void setHashMap(HashMap<String, Object> map,Object object) {
  try {
   BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
   PropertyDescriptor[] pros = beanInfo.getPropertyDescriptors();
   for (PropertyDescriptor des : pros) {
    String name = des.getName();
    if(name.equals("class")){
     continue;
    }
    Method write = des.getWriteMethod();
    Object value = map.get(name);
    //执行object中write对应的方法,传入的参数为  new Object[]{map.get(name)}
    write.invoke(object, new Object[]{map.get(name)});
   }
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}
测试代码:
GameRole crazy = new GameRole("crazy", 10, 10);
  System.out.println("=====crazy初始状态=======");
  crazy.print();
  System.out.println("=====crazy打怪过后=======");
  crazy.createMemo();
  crazy.setEnegy(8);
  crazy.setBlood(5);
  crazy.print();
  System.out.println("=====crazy恢复到先前状态======");
  crazy.backupMemo();
  crazy.print();

结果:

=====crazy初始状态=======
name:crazy blood:10 enegy:10
=====crazy打怪过后=======
pros4
name:crazy blood:5 enegy:8
=====crazy恢复到先前状态======
name:crazy blood:10 enegy:10
这样,一个能够保存多个属性的备忘录模式就做好了。这是你可能又会问,玩游戏的时候可以存很多个档啊,想恢复到那个就恢复到哪个。OK,我们就来实现一下。这个时候只要修改GameRole角色就好了。我们用HashMap类型来等级备忘录,并给每个备忘录写上名字。这样只要修改一下createMemo和backupMemo函数就行了。
public class GameRole2 {
 private HashMap<String, MemoRandum2> memos = new HashMap<String, MemoRandum2>();
 private String name = null ;
 private int enegy = 0;
 private int blood = 0;
 public GameRole2(String name,int enegy,int blood) {
  this.name = name ;
  this.enegy = enegy;
  this.blood = blood;
 }
 public void createMemo(String ids) {
  MemoRandum2 memoRandum2 = new MemoRandum2();
  memoRandum2.setPros(BeanUtil.getHashMap(this));
  this.memos.put(ids, memoRandum2);
 }
 public boolean backupMemo(String ids) {
  MemoRandum2 memoRandum2 = this.memos.get(ids);
  if(memoRandum2 != null){
   BeanUtil.setHashMap(memoRandum2.getPros(), this);
   return true;
  }else {
   return false;
  }
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getEnegy() {
  return enegy;
 }
 public void setEnegy(int enegy) {
  this.enegy = enegy;
 }
 public int getBlood() {
  return blood;
 }
 public void setBlood(int blood) {
  this.blood = blood;
 }
 public void print() {
  System.out.println("name:"+this.name+" blood:"+this.blood+" enegy:"+this.enegy);
 }
}
测试一下:
GameRole2 crazy2 = new GameRole2("crazy2", 10, 10);
  System.out.println("=====crazy2初始状态=======");
  crazy2.print();
  crazy2.createMemo("初始");
  System.out.println("=====crazy2打怪过后状态1=======");
  crazy2.setBlood(8);
  crazy2.setEnegy(4);
  crazy2.print();
  crazy2.createMemo("状态1");
  System.out.println("=====crazy2打怪过后状态2=======");
  crazy2.setBlood(7);
  crazy2.setEnegy(2);
  crazy2.print();
  crazy2.createMemo("状态2");
  System.out.println("=====crazy2恢复到初始状态======");
  crazy2.backupMemo("初始");
  crazy2.print();
  System.out.println("=====crazy2恢复到状态1======");
  crazy2.backupMemo("状态1");
  crazy2.print();
结果:
=====crazy2初始状态=======
name:crazy2 blood:10 enegy:10
pros4
=====crazy2打怪过后状态1=======
name:crazy2 blood:8 enegy:4
pros4
=====crazy2打怪过后状态2=======
name:crazy2 blood:7 enegy:2
pros4
=====crazy2恢复到初始状态======
name:crazy2 blood:10 enegy:10
=====crazy2恢复到状态1======
name:crazy2 blood:8 enegy:4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值