2006年03月23日

Memento ― 状態を保存する

  
ここに掲載したコードは、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』に掲載されているサンプルコードをC#に移植したものです。移植後のコードの公開に関しては、結城氏の了解を得ています。
※当ソースは、Visual C# 2005 Express Editionで動作を確認しています。



Mementoクラス
using System;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns.Game {

public class Memento {
private int money; // 所持金
private List<string> fruits; // フルーツ

// コンストラクタ(wide interface)
public Memento(int money) {
this.money = money;
this.fruits = new List<string>();
}

// 所持金を得る(narrow interface)
public virtual int Money {
get { return money; }

}

// フルーツを得る(wide interface)
public virtual List<string> Fruits {
get {
List<string> clone = new List<string>();
foreach (string s in fruits) {
clone.Add(s);
}
return clone;
}
}

// フルーツを追加する(wide interface)
public virtual void AddFruit(string fruit) {
fruits.Add(fruit);
}
}
}


Gamerクラス
using System;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns.Game {

public class Gamer {
private int money; // 所持金
private List<string> fruits = new List<string>(); // フルーツ
private Random random = new Random(); // 乱数発生器
private static string[] fruitsname =
new string[] { "リンゴ", "ぶどう", "バナナ", "みかん" };

// コンストラクタ
public Gamer(int money) {
this.money = money;
}

// 現在の所持金を得る
public virtual int Money {
get { return money; }
}

// フルーツを1個得る
private string GetFruit() {
string prefix = "";
if (random.Next(0, 2) == 0) {
prefix = "おいしい";
}
return prefix + fruitsname[random.Next(fruitsname.Length)];
}

public virtual void Bet() {
// 賭ける…ゲームの進行
int dice = random.Next(6) + 1; // サイコロを振る
if (dice == 1) {
// 1の目…所持金が増える
money += 100;
Console.WriteLine("所持金が増えました。");
} else if (dice == 2) {
// 2の目…所持金が半分になる
money /= 2;
Console.WriteLine("所持金が半分になりました。");
} else if (dice == 6) {
// 6の目…フルーツをもらう
string f = GetFruit();
Console.WriteLine("フルーツ(" + f + ")をもらいました。");
fruits.Add(f);
} else {
// それ以外…何も起きない
Console.WriteLine("何も起こりませんでした。");
}
}

// スナップショットをとる
public virtual Memento CreateMemento() {
Memento m = new Memento(money);
foreach (string f in fruits) {
if (f.StartsWith("おいしい")) {
// フルーツはおいしいものだけ保存
m.AddFruit(f);
}
}
return m;
}

// アンドゥを行う
public virtual void RestoreMemento(Memento memento) {
this.money = memento.Money;
this.fruits = memento.Fruits;
}

// 文字列表現
public override string ToString() {
string s = string.Join(", ", fruits.ToArray());

return string.Format("[money = {0}, fruits = [{1}]]", money, s);
}
}
}


Programクラス
using System;
using System.Threading;
using Gushwell.DesignPatterns.Game;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns {

public class Program {

public static void Main(string[] args) {
Gamer gamer = new Gamer(100); // 最初の所持金は100
Memento memento = gamer.CreateMemento(); // 最初の状態を保存しておく

for (int i = 0; i < 100; i++) {
Console.WriteLine("==== " + i); // 回数表示
Console.WriteLine("現状:" + gamer); // 現在の主人公の状態表示

gamer.Bet(); // ゲームを進める

Console.WriteLine("所持金は" + gamer.Money + "円になりました。");

// Mementoの取り扱いの決定
if (gamer.Money > memento.Money) {
Console.WriteLine(" (だいぶ増えたので、現在の状態を保存しておこう)");
memento = gamer.CreateMemento();
} else if (gamer.Money < memento.Money / 2) {
Console.WriteLine(" (だいぶ減ったので、以前の状態に復帰しよう)");
gamer.RestoreMemento(memento);
}

// 時間待ち
Thread.Sleep(1000);
Console.WriteLine("");
}
}
}
}



 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/50395621