设计模式:备忘录(Memento)模式

一、前言

  备忘录模式用于保存和恢复对象的状态,相信大家看过我前面的拙作就会想到原型模式也能保存一个对象在某一个时刻的状态,那么两者有何不同的呢?原型模式保存的是当前对象的所有状态信息,恢复的时候会生成与保存的对象完全相同的另外一个实例;而备忘录模式保存的是我们关心的在恢复时需要的对象的部分状态信息,相当于快照。备忘录模式大家肯定都见过,比如在玩游戏的时候有一个保存当前闯关的状态的功能,会对当前用户所处的状态进行保存,当用户闯关失败或者需要从快照的地方开始的时候,就能读取当时保存的状态完整地恢复到当时的环境,这一点和VMware上面的快照功能很类似。

二、代码

  Memento类:

 package zyr.dp.memento;

 import java.util.ArrayList;
import java.util.List; public class Memento { private int menoy;
private ArrayList fruits; //窄接口,访问部分信息
public int getMenoy(){
return menoy;
} //宽接口,本包之内皆可访问
Memento(int menoy){
this.menoy=menoy;
fruits=new ArrayList();//每次调用的时候重新生成,很重要
}
//宽接口,本包之内皆可访问
List getFruits(){
return (List) fruits.clone();
}
//宽接口,本包之内皆可访问
void addFruits(String fruit){
fruits.add(fruit);
} }
Gamer 类:
 package zyr.dp.memento;

 import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random; public class Gamer { private static String[] FruitsSame={"香蕉","苹果","橘子","柚子"}; private int menoy;
private List fruits=new ArrayList();
private Random random=new Random(); public int getMenoy(){
return menoy;
} public Gamer(int menoy){
this.menoy=menoy;
} public void bet(){
int next=random.nextInt(6)+1;
if(next==1){
menoy+=100;
System.out.println("金钱增加了100,当前金钱为:"+menoy);
}else if(next==2){
menoy/=2;
System.out.println("金钱减少了一半,当前金钱为:"+menoy);
}else if(next==6){
String f=getFruit();
fruits.add(f);
System.out.println("获得了水果:"+f+",当前金钱为:"+menoy);
}else {
System.out.println("金钱没有发生改变,当前金钱为:"+menoy);
}
} private String getFruit() { String prefix="";
if(random.nextBoolean()){
prefix="好吃的";
}
return prefix+FruitsSame[random.nextInt(FruitsSame.length)]; } public Memento createMemento(){
Memento m=new Memento(menoy);
Iterator it=fruits.iterator();
while(it.hasNext()){
String fruit=(String)it.next();
if(fruit.startsWith("好吃的")){
m.addFruits(fruit);
}
}
return m;
} public void restoreMemento(Memento memento){
this.menoy=memento.getMenoy();
this.fruits=memento.getFruits();
} public String toString(){
return "Menoy:"+menoy+" ,Fruits:"+fruits;
} }

 Main类:

 package zyr.dp.test;

 import zyr.dp.memento.Gamer;
import zyr.dp.memento.Memento; public class Main { public static void main(String[] args) {
Gamer gamer=new Gamer(100);
Memento memento=gamer.createMemento();
for(int i=0;i<100;i++){
System.out.println("当前状态:"+i);
System.out.println("当前金额:"+gamer.getMenoy());
gamer.bet();
if(gamer.getMenoy()<memento.getMenoy()/2){
System.out.println("金钱过少,恢复到以前的状态:");
gamer.restoreMemento(memento);
System.out.println("此时状态为:"+gamer);
}else if(gamer.getMenoy()>memento.getMenoy()){
System.out.println("金钱增多,保存当前状态:");
memento=gamer.createMemento();
System.out.println("此时状态为:"+gamer);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} } }

 运行结果:

当前状态:0
当前金额:100
金钱没有发生改变,当前金钱为:100
当前状态:1
当前金额:100
金钱增加了100,当前金钱为:200
金钱增多,保存当前状态:
此时状态为:Menoy:200 ,Fruits:[]
当前状态:2
当前金额:200
金钱增加了100,当前金钱为:300
金钱增多,保存当前状态:
此时状态为:Menoy:300 ,Fruits:[]
当前状态:3
当前金额:300
金钱减少了一半,当前金钱为:150
当前状态:4
当前金额:150
金钱减少了一半,当前金钱为:75
金钱过少,恢复到以前的状态:
此时状态为:Menoy:300 ,Fruits:[]
当前状态:5
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:6
当前金额:300
金钱增加了100,当前金钱为:400
金钱增多,保存当前状态:
此时状态为:Menoy:400 ,Fruits:[]
当前状态:7
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:8
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:9
当前金额:200
金钱增加了100,当前金钱为:300
当前状态:10
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:11
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:12
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:13
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:14
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:15
当前金额:300
金钱增加了100,当前金钱为:400
当前状态:16
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:17
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:18
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:19
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:20
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:21
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:22
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:23
当前金额:200
获得了水果:橘子,当前金钱为:200
当前状态:24
当前金额:200
金钱增加了100,当前金钱为:300
当前状态:25
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:26
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:27
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:28
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:29
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:30
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:31
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:32
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:33
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:34
当前金额:300
获得了水果:橘子,当前金钱为:300
当前状态:35
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:36
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:37
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:38
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:39
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:40
当前金额:300
金钱减少了一半,当前金钱为:150
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[]
当前状态:41
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:42
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:43
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:44
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:45
当前金额:200
金钱减少了一半,当前金钱为:100
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[]
当前状态:46
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:47
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:48
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:49
当前金额:400
获得了水果:香蕉,当前金钱为:400
当前状态:50
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:51
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:52
当前金额:200
金钱增加了100,当前金钱为:300
当前状态:53
当前金额:300
金钱减少了一半,当前金钱为:150
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[]
当前状态:54
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:55
当前金额:200
获得了水果:好吃的柚子,当前金钱为:200
当前状态:56
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:57
当前金额:200
获得了水果:好吃的香蕉,当前金钱为:200
当前状态:58
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:59
当前金额:200
获得了水果:香蕉,当前金钱为:200
当前状态:60
当前金额:200
获得了水果:苹果,当前金钱为:200
当前状态:61
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:62
当前金额:200
金钱增加了100,当前金钱为:300
当前状态:63
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:64
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:65
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:66
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:67
当前金额:300
金钱减少了一半,当前金钱为:150
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[]
当前状态:68
当前金额:400
金钱增加了100,当前金钱为:500
金钱增多,保存当前状态:
此时状态为:Menoy:500 ,Fruits:[]
当前状态:69
当前金额:500
金钱增加了100,当前金钱为:600
金钱增多,保存当前状态:
此时状态为:Menoy:600 ,Fruits:[]
当前状态:70
当前金额:600
金钱没有发生改变,当前金钱为:600
当前状态:71
当前金额:600
金钱没有发生改变,当前金钱为:600
当前状态:72
当前金额:600
金钱没有发生改变,当前金钱为:600
当前状态:73
当前金额:600
金钱增加了100,当前金钱为:700
金钱增多,保存当前状态:
此时状态为:Menoy:700 ,Fruits:[]
当前状态:74
当前金额:700
金钱增加了100,当前金钱为:800
金钱增多,保存当前状态:
此时状态为:Menoy:800 ,Fruits:[]
当前状态:75
当前金额:800
金钱没有发生改变,当前金钱为:800
当前状态:76
当前金额:800
获得了水果:好吃的柚子,当前金钱为:800
当前状态:77
当前金额:800
金钱没有发生改变,当前金钱为:800
当前状态:78
当前金额:800
金钱减少了一半,当前金钱为:400
当前状态:79
当前金额:400
金钱减少了一半,当前金钱为:200
金钱过少,恢复到以前的状态:
此时状态为:Menoy:800 ,Fruits:[]
当前状态:80
当前金额:800
获得了水果:好吃的苹果,当前金钱为:800
当前状态:81
当前金额:800
金钱没有发生改变,当前金钱为:800
当前状态:82
当前金额:800
金钱没有发生改变,当前金钱为:800
当前状态:83
当前金额:800
获得了水果:好吃的柚子,当前金钱为:800
当前状态:84
当前金额:800
金钱没有发生改变,当前金钱为:800
当前状态:85
当前金额:800
金钱没有发生改变,当前金钱为:800
当前状态:86
当前金额:800
金钱增加了100,当前金钱为:900
金钱增多,保存当前状态:
此时状态为:Menoy:900 ,Fruits:[好吃的苹果, 好吃的柚子]
当前状态:87
当前金额:900
金钱减少了一半,当前金钱为:450
当前状态:88
当前金额:450
金钱增加了100,当前金钱为:550
当前状态:89
当前金额:550
金钱增加了100,当前金钱为:650
当前状态:90
当前金额:650
金钱增加了100,当前金钱为:750
当前状态:91
当前金额:750
获得了水果:柚子,当前金钱为:750
当前状态:92
当前金额:750
金钱没有发生改变,当前金钱为:750
当前状态:93
当前金额:750
金钱增加了100,当前金钱为:850
当前状态:94
当前金额:850
金钱减少了一半,当前金钱为:425
金钱过少,恢复到以前的状态:
此时状态为:Menoy:900 ,Fruits:[好吃的苹果, 好吃的柚子]
当前状态:95
当前金额:900
获得了水果:好吃的橘子,当前金钱为:900
当前状态:96
当前金额:900
金钱没有发生改变,当前金钱为:900
当前状态:97
当前金额:900
金钱增加了100,当前金钱为:1000
金钱增多,保存当前状态:
此时状态为:Menoy:1000 ,Fruits:[好吃的苹果, 好吃的柚子, 好吃的橘子]
当前状态:98
当前金额:1000
金钱减少了一半,当前金钱为:500
当前状态:99
当前金额:500
金钱减少了一半,当前金钱为:250
金钱过少,恢复到以前的状态:
此时状态为:Menoy:1000 ,Fruits:[好吃的苹果, 好吃的柚子, 好吃的橘子]

运行结果

   本程序的功能是根据循环次数随机的生成1~6这6个数字,如果数字是1,则金钱加一百,如果是二,则金钱减半,如果是6,则随机生成水果,水果分为好吃的和不好吃的,在保存的时候只保存好吃的水果,恢复的时候就只有好吃的水果了。当金钱少于当前备忘录中金钱的一半的时候就要恢复到备忘录的状态;当金钱大于备忘录的状态的时候就要备份当前的状态,备份的时候只备份好的水果以及当前金额,这就是游戏的功能,可以看到运行的结果的正确性。

  这里有几点要注意:

   2.1、窄接口和宽接口

   在代码中我已经标注出了窄接口和宽接口,如何定义这两种接口还要看这两种接口前面的修饰符,如果是默认的(只有本包的类可以使用),并且这些接口结合到一起可以完全的将本类的信息显示出来,那么就是宽接口;只能在本包之中使用,如果修饰符是public的接口,并且只能表示本类一部分信息,因为是public可以在其他包中使用的,就是窄接口,只能查看部分信息,因此是窄的。如下图所示,对于Main类所在的包,只能使用其他两个类中声明为public的字段和方法,因此在Main中只能使用窄接口来完成一定信息的读取getMenoy()。这只是一个概念,强调的是类、字段、方法的可见性。

  2.2、可见性

   同时我们也知道,public修饰的字段和方法在任何包中都可以使用,private修饰的字段和方法只能在本类之中使用,protected修饰的方法可以在本包之中以及该类的子类(可以在其他包)中使用,默认的没有任何修饰的可以在本包之中使用。这就是四种修饰关键字的可见性。在编程的时候我们一定要考虑这些问题,不然就会导致我们不想看到的字段、方法、类被误用的结果。

  2.3、将备份内容存盘并且读取

 Memento类:

 package zyr.dp.serializable;

 import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; public class Memento implements Serializable {

private static final long serialVersionUID = 8497203738547925495L; private int menoy;
private ArrayList fruits; //窄接口,访问部分信息
public int getMenoy(){
return menoy;
} //宽接口,本包之内皆可访问
Memento(int menoy){
this.menoy=menoy;
fruits=new ArrayList();//每次调用的时候重新生成,很重要
}
//宽接口,本包之内皆可访问
List getFruits(){
return (List) fruits.clone();
}
//宽接口,本包之内皆可访问
void addFruits(String fruit){
fruits.add(fruit);
} }

 Gamer类:

 package zyr.dp.serializable;

 import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random; public class Gamer { private static String[] FruitsSame={"香蕉","苹果","橘子","柚子"}; private int menoy;
private List fruits=new ArrayList();
private Random random=new Random(); public int getMenoy(){
return menoy;
} public Gamer(int menoy){
this.menoy=menoy;
} public void bet(){
int next=random.nextInt(6)+1;
if(next==1){
menoy+=100;
System.out.println("金钱增加了100,当前金钱为:"+menoy);
}else if(next==2){
menoy/=2;
System.out.println("金钱减少了一半,当前金钱为:"+menoy);
}else if(next==6){
String f=getFruit();
fruits.add(f);
System.out.println("获得了水果:"+f+",当前金钱为:"+menoy);
}else {
System.out.println("金钱没有发生改变,当前金钱为:"+menoy);
}
} private String getFruit() { String prefix="";
if(random.nextBoolean()){
prefix="好吃的";
}
return prefix+FruitsSame[random.nextInt(FruitsSame.length)]; } public Memento createMemento(){
Memento m=new Memento(menoy);
Iterator it=fruits.iterator();
while(it.hasNext()){
String fruit=(String)it.next();
if(fruit.startsWith("好吃的")){
m.addFruits(fruit);
}
}
return m;
} public void restoreMemento(Memento memento){
this.menoy=memento.getMenoy();
this.fruits=memento.getFruits();
} public String toString(){
return "Menoy:"+menoy+" ,Fruits:"+fruits;
} }

 SerializableMain类:

 package zyr.dp.test;

 import java.io.*;

 import zyr.dp.serializable.Gamer;
import zyr.dp.serializable.Memento; public class SerializableMain { private static String filename="game.dat";
public static void main(String[] args) {
Gamer gamer=new Gamer(100);
Memento memento=loadMemento();

16 if(memento==null){
17 memento=gamer.createMemento();
18 }else{
19 System.out.println("从上次保存处开始...");
20 gamer.restoreMemento(memento);
21 }

for(int i=0;i<100;i++){
System.out.println("当前状态:"+i);
System.out.println("当前金额:"+gamer.getMenoy());
gamer.bet();
if(gamer.getMenoy()<memento.getMenoy()/2){
System.out.println("金钱过少,恢复到以前的状态:");
gamer.restoreMemento(memento);
System.out.println("此时状态为:"+gamer);
}else if(gamer.getMenoy()>memento.getMenoy()){
System.out.println("金钱增多,保存当前状态:");
memento=gamer.createMemento();
saveMemento(memento);
System.out.println("此时状态为:"+gamer);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
private static void saveMemento(Memento memento) {
try {
ObjectOutput o=new ObjectOutputStream(new FileOutputStream(filename));
o.writeObject(memento);
o.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static Memento loadMemento() {
Memento memento=null;
ObjectInput in;
try {
in = new ObjectInputStream(new FileInputStream(filename));
memento=(Memento)in.readObject();
in.close();
} catch (FileNotFoundException e) {
System.out.println(e.toString());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return memento;
}

}

运行结果:

初次运行:

java.io.FileNotFoundException: game.dat (系统找不到指定的文件。)
当前状态:0
当前金额:100
获得了水果:好吃的苹果,当前金钱为:100
当前状态:1
当前金额:100
金钱没有发生改变,当前金钱为:100
当前状态:2
当前金额:100
金钱没有发生改变,当前金钱为:100
当前状态:3
当前金额:100
金钱没有发生改变,当前金钱为:100
当前状态:4
当前金额:100
获得了水果:苹果,当前金钱为:100
当前状态:5
当前金额:100
金钱没有发生改变,当前金钱为:100
当前状态:6
当前金额:100
金钱增加了100,当前金钱为:200
金钱增多,保存当前状态:
此时状态为:Menoy:200 ,Fruits:[好吃的苹果, 苹果]
当前状态:7
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:8
当前金额:200
金钱增加了100,当前金钱为:300
金钱增多,保存当前状态:
此时状态为:Menoy:300 ,Fruits:[好吃的苹果, 苹果]
当前状态:9
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:10
当前金额:300
获得了水果:橘子,当前金钱为:300
当前状态:11
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:12
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:13
当前金额:300
金钱增加了100,当前金钱为:400
金钱增多,保存当前状态:
此时状态为:Menoy:400 ,Fruits:[好吃的苹果, 苹果, 橘子]
当前状态:14
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:15
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:16
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:17
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:18
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:19
当前金额:200
获得了水果:好吃的柚子,当前金钱为:200
当前状态:20
当前金额:200
获得了水果:好吃的柚子,当前金钱为:200
当前状态:21
当前金额:200
金钱减少了一半,当前金钱为:100
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[好吃的苹果]
当前状态:22
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:23
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:24
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:25
当前金额:200
金钱增加了100,当前金钱为:300
当前状态:26
当前金额:300
金钱没有发生改变,当前金钱为:300
当前状态:27
当前金额:300
金钱减少了一半,当前金钱为:150
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[好吃的苹果]
当前状态:28
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:29
当前金额:400
获得了水果:香蕉,当前金钱为:400
当前状态:30
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:31
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:32
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:33
当前金额:200
获得了水果:柚子,当前金钱为:200
当前状态:34
当前金额:200
金钱减少了一半,当前金钱为:100
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[好吃的苹果]
当前状态:35
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:36
当前金额:400
获得了水果:橘子,当前金钱为:400
当前状态:37
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:38
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:39
当前金额:200
获得了水果:好吃的橘子,当前金钱为:200
当前状态:40
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:41
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:42
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:43
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:44
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:45
当前金额:200
金钱增加了100,当前金钱为:300
当前状态:46
当前金额:300
金钱减少了一半,当前金钱为:150
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[好吃的苹果]
当前状态:47
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:48
当前金额:400
金钱减少了一半,当前金钱为:200
当前状态:49
当前金额:200
获得了水果:柚子,当前金钱为:200
当前状态:50
当前金额:200
金钱没有发生改变,当前金钱为:200
当前状态:51
当前金额:200
金钱减少了一半,当前金钱为:100
金钱过少,恢复到以前的状态:
此时状态为:Menoy:400 ,Fruits:[好吃的苹果]
当前状态:52
当前金额:400
获得了水果:香蕉,当前金钱为:400
当前状态:53
当前金额:400
金钱没有发生改变,当前金钱为:400
当前状态:54
当前金额:400
金钱增加了100,当前金钱为:500
金钱增多,保存当前状态:
此时状态为:Menoy:500 ,Fruits:[好吃的苹果, 香蕉]
当前状态:55
当前金额:500
金钱减少了一半,当前金钱为:250
当前状态:56
当前金额:250
获得了水果:好吃的苹果,当前金钱为:250
当前状态:57
当前金额:250
金钱减少了一半,当前金钱为:125
金钱过少,恢复到以前的状态:
此时状态为:Menoy:500 ,Fruits:[好吃的苹果]
当前状态:58
当前金额:500
金钱没有发生改变,当前金钱为:500
当前状态:59
当前金额:500
获得了水果:柚子,当前金钱为:500
当前状态:60
当前金额:500
金钱减少了一半,当前金钱为:250
当前状态:61
当前金额:250
金钱没有发生改变,当前金钱为:250
当前状态:62
当前金额:250
金钱增加了100,当前金钱为:350
当前状态:63
当前金额:350
金钱没有发生改变,当前金钱为:350
当前状态:64
当前金额:350
金钱减少了一半,当前金钱为:175
金钱过少,恢复到以前的状态:
此时状态为:Menoy:500 ,Fruits:[好吃的苹果]
当前状态:65
当前金额:500
获得了水果:柚子,当前金钱为:500
当前状态:66
当前金额:500
金钱增加了100,当前金钱为:600
金钱增多,保存当前状态:
此时状态为:Menoy:600 ,Fruits:[好吃的苹果, 柚子]
当前状态:67
当前金额:600
金钱没有发生改变,当前金钱为:600
当前状态:68
当前金额:600
金钱增加了100,当前金钱为:700
金钱增多,保存当前状态:
此时状态为:Menoy:700 ,Fruits:[好吃的苹果, 柚子]
当前状态:69
当前金额:700
获得了水果:好吃的橘子,当前金钱为:700
当前状态:70
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:71
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:72
当前金额:700
获得了水果:香蕉,当前金钱为:700
当前状态:73
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:74
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:75
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:76
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:77
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:78
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:79
当前金额:700
金钱没有发生改变,当前金钱为:700
当前状态:80
当前金额:700
金钱增加了100,当前金钱为:800
金钱增多,保存当前状态:
此时状态为:Menoy:800 ,Fruits:[好吃的苹果, 柚子, 好吃的橘子, 香蕉]
当前状态:81
当前金额:800
金钱增加了100,当前金钱为:900
金钱增多,保存当前状态:
此时状态为:Menoy:900 ,Fruits:[好吃的苹果, 柚子, 好吃的橘子, 香蕉]
当前状态:82
当前金额:900
金钱没有发生改变,当前金钱为:900
当前状态:83
当前金额:900
获得了水果:柚子,当前金钱为:900
当前状态:84
当前金额:900
金钱减少了一半,当前金钱为:450
当前状态:85
当前金额:450
金钱没有发生改变,当前金钱为:450
当前状态:86
当前金额:450
金钱增加了100,当前金钱为:550
当前状态:87
当前金额:550
获得了水果:好吃的柚子,当前金钱为:550
当前状态:88
当前金额:550
金钱没有发生改变,当前金钱为:550
当前状态:89
当前金额:550
金钱没有发生改变,当前金钱为:550
当前状态:90
当前金额:550
金钱没有发生改变,当前金钱为:550
当前状态:91
当前金额:550
获得了水果:好吃的香蕉,当前金钱为:550
当前状态:92
当前金额:550
金钱减少了一半,当前金钱为:275
金钱过少,恢复到以前的状态:
此时状态为:Menoy:900 ,Fruits:[好吃的苹果, 好吃的橘子]
当前状态:93
当前金额:900
金钱增加了100,当前金钱为:1000
金钱增多,保存当前状态:
此时状态为:Menoy:1000 ,Fruits:[好吃的苹果, 好吃的橘子]
当前状态:94
当前金额:1000
获得了水果:橘子,当前金钱为:1000
当前状态:95
当前金额:1000
金钱减少了一半,当前金钱为:500
当前状态:96
当前金额:500
金钱没有发生改变,当前金钱为:500
当前状态:97
当前金额:500
金钱没有发生改变,当前金钱为:500
当前状态:98
当前金额:500
获得了水果:柚子,当前金钱为:500
当前状态:99
当前金额:500
获得了水果:柚子,当前金钱为:500

 第二次运行:

从上次保存处开始...
当前状态:0
当前金额:1000
金钱没有发生改变,当前金钱为:1000
当前状态:1
当前金额:1000
金钱增加了100,当前金钱为:1100
金钱增多,保存当前状态:
此时状态为:Menoy:1100 ,Fruits:[好吃的苹果, 好吃的橘子]
当前状态:2
当前金额:1100
金钱增加了100,当前金钱为:1200
金钱增多,保存当前状态:
此时状态为:Menoy:1200 ,Fruits:[好吃的苹果, 好吃的橘子]
当前状态:3
当前金额:1200
获得了水果:香蕉,当前金钱为:1200
当前状态:4
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:5
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:6
当前金额:1200
获得了水果:好吃的橘子,当前金钱为:1200
当前状态:7
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:8
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:9
当前金额:1200
获得了水果:好吃的苹果,当前金钱为:1200
当前状态:10
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:11
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:12
当前金额:1200
获得了水果:好吃的橘子,当前金钱为:1200
当前状态:13
当前金额:1200
获得了水果:好吃的柚子,当前金钱为:1200
当前状态:14
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:15
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:16
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:17
当前金额:1200
获得了水果:苹果,当前金钱为:1200
当前状态:18
当前金额:1200
金钱没有发生改变,当前金钱为:1200
当前状态:19
当前金额:1200
金钱增加了100,当前金钱为:1300
金钱增多,保存当前状态:
此时状态为:Menoy:1300 ,Fruits:[好吃的苹果, 好吃的橘子, 香蕉, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子, 苹果]
当前状态:20
当前金额:1300
金钱没有发生改变,当前金钱为:1300
当前状态:21
当前金额:1300
金钱减少了一半,当前金钱为:650
当前状态:22
当前金额:650
获得了水果:好吃的苹果,当前金钱为:650
当前状态:23
当前金额:650
金钱增加了100,当前金钱为:750
当前状态:24
当前金额:750
金钱减少了一半,当前金钱为:375
金钱过少,恢复到以前的状态:
此时状态为:Menoy:1300 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:25
当前金额:1300
金钱没有发生改变,当前金钱为:1300
当前状态:26
当前金额:1300
金钱增加了100,当前金钱为:1400
金钱增多,保存当前状态:
此时状态为:Menoy:1400 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:27
当前金额:1400
金钱没有发生改变,当前金钱为:1400
当前状态:28
当前金额:1400
金钱没有发生改变,当前金钱为:1400
当前状态:29
当前金额:1400
金钱增加了100,当前金钱为:1500
金钱增多,保存当前状态:
此时状态为:Menoy:1500 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:30
当前金额:1500
金钱增加了100,当前金钱为:1600
金钱增多,保存当前状态:
此时状态为:Menoy:1600 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:31
当前金额:1600
金钱没有发生改变,当前金钱为:1600
当前状态:32
当前金额:1600
金钱没有发生改变,当前金钱为:1600
当前状态:33
当前金额:1600
金钱没有发生改变,当前金钱为:1600
当前状态:34
当前金额:1600
金钱增加了100,当前金钱为:1700
金钱增多,保存当前状态:
此时状态为:Menoy:1700 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:35
当前金额:1700
金钱没有发生改变,当前金钱为:1700
当前状态:36
当前金额:1700
金钱没有发生改变,当前金钱为:1700
当前状态:37
当前金额:1700
金钱没有发生改变,当前金钱为:1700
当前状态:38
当前金额:1700
金钱减少了一半,当前金钱为:850
当前状态:39
当前金额:850
金钱没有发生改变,当前金钱为:850
当前状态:40
当前金额:850
金钱没有发生改变,当前金钱为:850
当前状态:41
当前金额:850
金钱没有发生改变,当前金钱为:850
当前状态:42
当前金额:850
金钱没有发生改变,当前金钱为:850
当前状态:43
当前金额:850
金钱增加了100,当前金钱为:950
当前状态:44
当前金额:950
金钱减少了一半,当前金钱为:475
金钱过少,恢复到以前的状态:
此时状态为:Menoy:1700 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:45
当前金额:1700
金钱没有发生改变,当前金钱为:1700
当前状态:46
当前金额:1700
金钱没有发生改变,当前金钱为:1700
当前状态:47
当前金额:1700
金钱没有发生改变,当前金钱为:1700
当前状态:48
当前金额:1700
金钱没有发生改变,当前金钱为:1700
当前状态:49
当前金额:1700
金钱增加了100,当前金钱为:1800
金钱增多,保存当前状态:
此时状态为:Menoy:1800 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:50
当前金额:1800
金钱减少了一半,当前金钱为:900
当前状态:51
当前金额:900
金钱没有发生改变,当前金钱为:900
当前状态:52
当前金额:900
金钱没有发生改变,当前金钱为:900
当前状态:53
当前金额:900
金钱没有发生改变,当前金钱为:900
当前状态:54
当前金额:900
获得了水果:好吃的柚子,当前金钱为:900
当前状态:55
当前金额:900
金钱没有发生改变,当前金钱为:900
当前状态:56
当前金额:900
金钱没有发生改变,当前金钱为:900
当前状态:57
当前金额:900
获得了水果:好吃的柚子,当前金钱为:900
当前状态:58
当前金额:900
金钱减少了一半,当前金钱为:450
金钱过少,恢复到以前的状态:
此时状态为:Menoy:1800 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:59
当前金额:1800
金钱增加了100,当前金钱为:1900
金钱增多,保存当前状态:
此时状态为:Menoy:1900 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:60
当前金额:1900
金钱没有发生改变,当前金钱为:1900
当前状态:61
当前金额:1900
金钱没有发生改变,当前金钱为:1900
当前状态:62
当前金额:1900
金钱没有发生改变,当前金钱为:1900
当前状态:63
当前金额:1900
获得了水果:好吃的柚子,当前金钱为:1900
当前状态:64
当前金额:1900
金钱没有发生改变,当前金钱为:1900
当前状态:65
当前金额:1900
金钱减少了一半,当前金钱为:950
当前状态:66
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:67
当前金额:950
获得了水果:柚子,当前金钱为:950
当前状态:68
当前金额:950
金钱减少了一半,当前金钱为:475
金钱过少,恢复到以前的状态:
此时状态为:Menoy:1900 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:69
当前金额:1900
金钱减少了一半,当前金钱为:950
当前状态:70
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:71
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:72
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:73
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:74
当前金额:950
金钱增加了100,当前金钱为:1050
当前状态:75
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:76
当前金额:1050
获得了水果:好吃的香蕉,当前金钱为:1050
当前状态:77
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:78
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:79
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:80
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:81
当前金额:1050
获得了水果:柚子,当前金钱为:1050
当前状态:82
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:83
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:84
当前金额:1050
金钱增加了100,当前金钱为:1150
当前状态:85
当前金额:1150
金钱没有发生改变,当前金钱为:1150
当前状态:86
当前金额:1150
金钱增加了100,当前金钱为:1250
当前状态:87
当前金额:1250
金钱减少了一半,当前金钱为:625
金钱过少,恢复到以前的状态:
此时状态为:Menoy:1900 ,Fruits:[好吃的苹果, 好吃的橘子, 好吃的橘子, 好吃的苹果, 好吃的橘子, 好吃的柚子]
当前状态:88
当前金额:1900
获得了水果:苹果,当前金钱为:1900
当前状态:89
当前金额:1900
金钱减少了一半,当前金钱为:950
当前状态:90
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:91
当前金额:950
获得了水果:好吃的橘子,当前金钱为:950
当前状态:92
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:93
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:94
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:95
当前金额:950
金钱没有发生改变,当前金钱为:950
当前状态:96
当前金额:950
获得了水果:好吃的橘子,当前金钱为:950
当前状态:97
当前金额:950
金钱增加了100,当前金钱为:1050
当前状态:98
当前金额:1050
金钱没有发生改变,当前金钱为:1050
当前状态:99
当前金额:1050
金钱没有发生改变,当前金钱为:1050

第二次运行

  可以看到保存和读取成功。

三、总结

  备忘录模式也是一种比较常用的模式用来保存对象的部分用于恢复的信息,和原型模式有着本质的区别,广泛运用在快照功能之中,另外我们知道了宽接口和窄接口,这里的接口就是指的方法,没有其他意思,以及类的可见性。同样的使用备忘录模式可以使得程序可以组件化,比如打算多次撤销当前的状态,以及不仅可以撤销而且可以将当前的状态保存到文件之中的时候,我们不需要修改Gamer的代码就能做到,职责明确是一种非常重要的是软件工程思想。

  程序代码

设计模式:备忘录(Memento)模式的更多相关文章

  1. C++设计模式实现--备忘录(Memento)模式

    一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态.并在该对象之外保存这个状态. 这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比較适用于功 ...

  2. 设计模式C++描述----17.备忘录(Memento)模式

    一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比较适用于功能 ...

  3. 大话设计模式--备忘录 Memento -- C++实现实例

    1. 备忘录: 在不破坏封装性的前提下, 捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后可将该对象恢复到原先保存的状态. Originator 发起人: 负责创建一个备忘录Memento ...

  4. 备忘录(Memento)模式

    备忘录模式又叫做快照模式或者Token模式. 备忘录对象是一个用来存储另一个对象内部状态的快照的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化,存储起来,从而可以在将来 ...

  5. 设计模式之——Memento模式

    Memento模式即快照模式,就是在某一时刻,设定一个状态,在后面随时可以返回到当前状态的模式. 我们拿一个闯关游戏作为举例,一共有十关,每闯一关,玩家所持金额增加一百,而闯关失败就扣一百.初始时,给 ...

  6. Java设计模式之从[暗黑破坏神存档点]分析备忘录(Memento)模式

    在大部分游戏中,都有一个"存档点"的概念.比如,在挑战boss前,游戏会在某个地方存档,假设玩家挑战boss失败,则会从这个存档点開始又一次游戏.因此,我们能够将这个"存 ...

  7. 设计模式:memento模式

    目的:在不破坏系统封装性的前提下,记录系统每一步的状态,可以做到状态回退和前进 方法: 定义一个数据类,保存所有相关数据 定义一个管理类,提供保存和恢复的接口 具体操作类调用管理类的保存和恢复接口 例 ...

  8. 设计模式 ( 十三 ) 命令模式Command(对象行为型)

    设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述         在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需 ...

  9. [工作中的设计模式]备忘录模式memento

    一.模式解析 备忘录对象是一个用来存储另外一个对象内部状态的快照的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把 ...

  10. 设计模式20---设计模式之备忘录模式(Memento)(行为型)

    1.讲解备忘录模式 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式,是GoF的23种设计模式之一,属于行为模式. 1.1定义 在不破坏封 ...

随机推荐

  1. 解决JavaScript拖动时同时触发点击事件的BUG

    在做在线地图项目的时候,在给marker点绑定事件时,因为有点击事件click,同时又存在拖动dragEnd事件,首先没有重大缺陷,就是在用户在点击的时候,有时候本想是点击,但是他触发了drag的事件 ...

  2. php 内存共享shmop源码阅读

    多进程通信的时候,会涉及到共享内存.shmop_open()创建或打开一个内存块 PHP_FUNCTION(shmop_open) { long key, mode, size; struct php ...

  3. orcale 之 多表查询

    在以往的工作中我们不可能单一的从一张表中查询数据,而在开始设计数据库的时候,我们会把一些数据存放在不同的数据表中,因此往往需要从多个数据表中获取到我们想要的数据. 笛卡儿积 在学习这些之前我们先了解一 ...

  4. 8.14_end

    the first interview 事件委托(ul.li) jsonp原理实现 印象最深的项目 each的实现 ajax的实现 性能优化的方法 判断Function和Boolean 印象最深的项目 ...

  5. 《c++primer》疑惑记录

    第4章 96页,数组维数为变量 第8章 246. IO对象不可复制.赋值原因是类设计时复制构造函数.赋值函数是私有的,为什么这么设计呢? 251. tie举例 第15章 484 派生类可以恢复,但不可 ...

  6. vue-cli 基础搭建

    1.安装node 2.npm install webpack -g 3.npm install vue-cli -g 4.然后进入到文件下边 vue init webpack 文件名字 5.进入工程文 ...

  7. 安装并开启ssh服务

    sudo yum install openssh*    安装 2. 设置 sudo vi /etc/ssh/sshd_config 首先先把port改掉port 52222 限制用户AllowUse ...

  8. Spring - 几种RPC模型的使用与比较

    Spring中,用JMS搞RPC时会用到: org.springframework.jms.remoting.JmsInvokerServiceExporter org.springframework ...

  9. mysql根据时间查询日期的优化

    例如查询昨日新注册用户,写法有如下两种: EXPLAIN select * from chess_user u where DATE_FORMAT(u.register_time,'%Y-%m-%d' ...

  10. JBPM学习第4篇:10分钟熟悉Eclipse

    http://download.jboss.org/jbpm/videos/7.0.0.Final_eclipse_getting_started.swf 打开视频练习 1.导入 evaluation ...