おーみんブログ

C#, ASP.NET Core, Unityが大好きです。

C#でMementoパターンを体験してみた。

はじめに

GoFデザインパターンの1つであるMementoパターンを体験してみました。

Mementoパターンとは

Mementoパターンでは、インスタンスの特定の状態を記憶し、必要な時に取り出すことができるようにするデザインパターンです。 特定の状態をスナップショットとして保存しておき、必要な時に復元するというような感じですね。

登場人物は3つあります。以下の記事がとても分かりやすかったので引用させていただきます。

www.itsenka.com

  1. Originator(作成者) 自分の状態を保存した「Memento」を作成します。(createMemento) また、要求された「Memento」に状態を戻します。(setMemento) 自身の状態を「Memento」として保持する・与えられた「Memento」から自身の状態を復元するという役割を担います。
  2. Memento(形見・記念品) 「Originator」の内部情報(フィールド値)を保持します。「Memento」は「Originator」と親密な関係にあります。(内部情報にアクセス)
  3. Caretaker(世話人) 「Originator」の状態を保存したい場合・ある時点に戻したい場合は、「Originator」に指示を出します。保存するように指示をだした場合は、その時点の状態の「Memento」を受取り、保持します。(履歴の管理も可能) 「Memento」を保持するタイミング・アンドゥするタイミング・「Memento」を保持するという役割を担います。

サンプルコード

以下のサンプルコードでは上記の3つの登場人物に沿ってクラスを作成しています。2回食事をし、最初に食べたものを思い出すというサンプルコードになっています。

// Caretaker
public class Program
{
    private static Dictionary<string, Memento> keyValuePairs = new();
    static void Main()
    {
        Console.WriteLine("朝食は何を食べようかな。");
        Food food = new();
        food.PrepareFood("パン");
        //最初に食べたものを記憶する
        keyValuePairs.Add("最初に食べたもの", food.CreateMemento());
        food.PrepareFood("卵焼き");
        //2番目に食べたものを記憶する
        keyValuePairs.Add("2番目に食べたもの", food.CreateMemento());
        Console.WriteLine("最初に何を食べたんだっけ?");
        food.SetMemento(keyValuePairs["最初に食べたもの"]);
        Console.WriteLine("最初に食べたものは・・・");
        Console.WriteLine(food.DisplayFood());
    }
}

// Originator
public class Food
{
    private string _morningFood;
    public void PrepareFood(string morningFood) => _morningFood = morningFood;
    public string DisplayFood() => _morningFood;
    public Memento CreateMemento() => new(_morningFood);
    public void SetMemento(Memento memento) => _morningFood = memento.Str;
}

// Memento
public class Memento
{
    public string Str { get; }
    public Memento(string str) => Str = str;
}
朝食は何を食べようかな。
最初に何を食べたんだっけ?
最初に食べたものは・・・
パン

おわりに

なるほど...確かにFoodインスタンスが変更されても元の情報を復元できていることが分かります。 頭の片隅にとどめておくようにします。