設計模式:備忘錄(Memento)模式
一、前言
備忘錄模式用於保存和恢復對象的狀態,相信大家看過我前面的拙作就會想到原型模式也能保存一個對象在某一個時刻的狀態,那么兩者有何不同的呢?原型模式保存的是當前對象的所有狀態信息,恢復的時候會生成與保存的對象完全相同的另外一個實例;而備忘錄模式保存的是我們關心的在恢復時需要的對象的部分狀態信息,相當於快照。備忘錄模式大家肯定都見過,比如在玩游戲的時候有一個保存當前闖關的狀態的功能,會對當前用戶所處的狀態進行保存,當用戶闖關失敗或者需要從快照的地方開始的時候,就能讀取當時保存的狀態完整地恢復到當時的環境,這一點和VMware上面的快照功能很類似。

二、代碼
Memento類:
1 package zyr.dp.memento; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class Memento { 7 8 private int menoy; 9 private ArrayList fruits; 10 11 //窄接口,訪問部分信息 12 public int getMenoy(){ 13 return menoy; 14 } 15 16 //寬接口,本包之內皆可訪問 17 Memento(int menoy){ 18 this.menoy=menoy; 19 fruits=new ArrayList();//每次調用的時候重新生成,很重要 20 } 21 //寬接口,本包之內皆可訪問 22 List getFruits(){ 23 return (List) fruits.clone(); 24 } 25 //寬接口,本包之內皆可訪問 26 void addFruits(String fruit){ 27 fruits.add(fruit); 28 } 29 30 }
Gamer 類:
1 package zyr.dp.memento; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 import java.util.List; 6 import java.util.Random; 7 8 public class Gamer { 9 10 private static String[] FruitsSame={"香蕉","蘋果","橘子","柚子"}; 11 12 private int menoy; 13 private List fruits=new ArrayList(); 14 private Random random=new Random(); 15 16 public int getMenoy(){ 17 return menoy; 18 } 19 20 public Gamer(int menoy){ 21 this.menoy=menoy; 22 } 23 24 public void bet(){ 25 int next=random.nextInt(6)+1; 26 if(next==1){ 27 menoy+=100; 28 System.out.println("金錢增加了100,當前金錢為:"+menoy); 29 }else if(next==2){ 30 menoy/=2; 31 System.out.println("金錢減少了一半,當前金錢為:"+menoy); 32 }else if(next==6){ 33 String f=getFruit(); 34 fruits.add(f); 35 System.out.println("獲得了水果:"+f+",當前金錢為:"+menoy); 36 }else { 37 System.out.println("金錢沒有發生改變,當前金錢為:"+menoy); 38 } 39 } 40 41 private String getFruit() { 42 43 String prefix=""; 44 if(random.nextBoolean()){ 45 prefix="好吃的"; 46 } 47 return prefix+FruitsSame[random.nextInt(FruitsSame.length)]; 48 49 } 50 51 public Memento createMemento(){ 52 Memento m=new Memento(menoy); 53 Iterator it=fruits.iterator(); 54 while(it.hasNext()){ 55 String fruit=(String)it.next(); 56 if(fruit.startsWith("好吃的")){ 57 m.addFruits(fruit); 58 } 59 } 60 return m; 61 } 62 63 public void restoreMemento(Memento memento){ 64 this.menoy=memento.getMenoy(); 65 this.fruits=memento.getFruits(); 66 } 67 68 public String toString(){ 69 return "Menoy:"+menoy+" ,Fruits:"+fruits; 70 } 71 72 }
Main類:
1 package zyr.dp.test; 2 3 import zyr.dp.memento.Gamer; 4 import zyr.dp.memento.Memento; 5 6 public class Main { 7 8 public static void main(String[] args) { 9 Gamer gamer=new Gamer(100); 10 Memento memento=gamer.createMemento(); 11 for(int i=0;i<100;i++){ 12 System.out.println("當前狀態:"+i); 13 System.out.println("當前金額:"+gamer.getMenoy()); 14 gamer.bet(); 15 if(gamer.getMenoy()<memento.getMenoy()/2){ 16 System.out.println("金錢過少,恢復到以前的狀態:"); 17 gamer.restoreMemento(memento); 18 System.out.println("此時狀態為:"+gamer); 19 }else if(gamer.getMenoy()>memento.getMenoy()){ 20 System.out.println("金錢增多,保存當前狀態:"); 21 memento=gamer.createMemento(); 22 System.out.println("此時狀態為:"+gamer); 23 } 24 try { 25 Thread.sleep(500); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 } 30 31 } 32 33 }
運行結果:
當前狀態: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類:
1 package zyr.dp.serializable; 2 3 import java.io.Serializable; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 public class Memento implements Serializable { 8 9 private static final long serialVersionUID = 8497203738547925495L; 10 11 private int menoy; 12 private ArrayList fruits; 13 14 //窄接口,訪問部分信息 15 public int getMenoy(){ 16 return menoy; 17 } 18 19 //寬接口,本包之內皆可訪問 20 Memento(int menoy){ 21 this.menoy=menoy; 22 fruits=new ArrayList();//每次調用的時候重新生成,很重要 23 } 24 //寬接口,本包之內皆可訪問 25 List getFruits(){ 26 return (List) fruits.clone(); 27 } 28 //寬接口,本包之內皆可訪問 29 void addFruits(String fruit){ 30 fruits.add(fruit); 31 } 32 33 }
Gamer類:
1 package zyr.dp.serializable; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 import java.util.List; 6 import java.util.Random; 7 8 public class Gamer { 9 10 private static String[] FruitsSame={"香蕉","蘋果","橘子","柚子"}; 11 12 private int menoy; 13 private List fruits=new ArrayList(); 14 private Random random=new Random(); 15 16 public int getMenoy(){ 17 return menoy; 18 } 19 20 public Gamer(int menoy){ 21 this.menoy=menoy; 22 } 23 24 public void bet(){ 25 int next=random.nextInt(6)+1; 26 if(next==1){ 27 menoy+=100; 28 System.out.println("金錢增加了100,當前金錢為:"+menoy); 29 }else if(next==2){ 30 menoy/=2; 31 System.out.println("金錢減少了一半,當前金錢為:"+menoy); 32 }else if(next==6){ 33 String f=getFruit(); 34 fruits.add(f); 35 System.out.println("獲得了水果:"+f+",當前金錢為:"+menoy); 36 }else { 37 System.out.println("金錢沒有發生改變,當前金錢為:"+menoy); 38 } 39 } 40 41 private String getFruit() { 42 43 String prefix=""; 44 if(random.nextBoolean()){ 45 prefix="好吃的"; 46 } 47 return prefix+FruitsSame[random.nextInt(FruitsSame.length)]; 48 49 } 50 51 public Memento createMemento(){ 52 Memento m=new Memento(menoy); 53 Iterator it=fruits.iterator(); 54 while(it.hasNext()){ 55 String fruit=(String)it.next(); 56 if(fruit.startsWith("好吃的")){ 57 m.addFruits(fruit); 58 } 59 } 60 return m; 61 } 62 63 public void restoreMemento(Memento memento){ 64 this.menoy=memento.getMenoy(); 65 this.fruits=memento.getFruits(); 66 } 67 68 public String toString(){ 69 return "Menoy:"+menoy+" ,Fruits:"+fruits; 70 } 71 72 }
SerializableMain類:
1 package zyr.dp.test; 2 3 import java.io.*; 4 5 import zyr.dp.serializable.Gamer; 6 import zyr.dp.serializable.Memento; 7 8 9 public class SerializableMain { 10 11 private static String filename="game.dat"; 12 public static void main(String[] args) { 13 Gamer gamer=new Gamer(100); 14 Memento memento=loadMemento(); 15 16 if(memento==null){ 17 memento=gamer.createMemento(); 18 }else{ 19 System.out.println("從上次保存處開始..."); 20 gamer.restoreMemento(memento); 21 } 22 23 for(int i=0;i<100;i++){ 24 System.out.println("當前狀態:"+i); 25 System.out.println("當前金額:"+gamer.getMenoy()); 26 gamer.bet(); 27 if(gamer.getMenoy()<memento.getMenoy()/2){ 28 System.out.println("金錢過少,恢復到以前的狀態:"); 29 gamer.restoreMemento(memento); 30 System.out.println("此時狀態為:"+gamer); 31 }else if(gamer.getMenoy()>memento.getMenoy()){ 32 System.out.println("金錢增多,保存當前狀態:"); 33 memento=gamer.createMemento(); 34 saveMemento(memento); 35 System.out.println("此時狀態為:"+gamer); 36 } 37 try { 38 Thread.sleep(500); 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } 42 } 43 44 } 45 private static void saveMemento(Memento memento) { 46 try { 47 ObjectOutput o=new ObjectOutputStream(new FileOutputStream(filename)); 48 o.writeObject(memento); 49 o.close(); 50 } catch (FileNotFoundException e) { 51 e.printStackTrace(); 52 } catch (IOException e) { 53 e.printStackTrace(); 54 } 55 } 56 private static Memento loadMemento() { 57 Memento memento=null; 58 ObjectInput in; 59 try { 60 in = new ObjectInputStream(new FileInputStream(filename)); 61 memento=(Memento)in.readObject(); 62 in.close(); 63 } catch (FileNotFoundException e) { 64 System.out.println(e.toString()); 65 } catch (IOException e) { 66 e.printStackTrace(); 67 } catch (ClassNotFoundException e) { 68 e.printStackTrace(); 69 } 70 return memento; 71 } 72 73 }
運行結果:
初次運行:
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的代碼就能做到,職責明確是一種非常重要的是軟件工程思想。
