2012-01-24 13 views

答えて

15

一般的なメモを実装することで、ジェネリックが明らかになります。一般的なメモは、必要なオブジェクトに使用できます。あなたが表示されます

多くの例が、それは不変ある.NETのいくつかの種類の一つですので、問題となる状態として(現在はこの質問への回答の中で、すべてのものを含む)の文字列を使用します。 (セッター・プロパティを持つ任意の参照型のような)可変オブジェクトを扱う場合

あなたはあなたがオブジェクトのdeepcopyを作成する必要が記念品を保存するときにかかわらず、覚えておく必要があります。それ以外の場合は、元のオブジェクトを変更するたびにあなたのメモを変更します。

protobuf-netまたはjson.netのようなシリアライザを使用すると、通常の.netシリアル化メカニズムのようにシリアル化可能な属性でオブジェクトをマークする必要がないため、これを実行できます。

CodeProjectのは、一般的な記念品の実装に関するいくつかの記事を持っているが、彼らはdeepcopy部分をスキップする傾向がある:

Generic Memento Pattern for Undo-Redo in C#

Memento Design Pattern

+0

ディープコピー部分に関する追加情報を追加できますか?実装のこの部分の例へのリンクまたは何か。グレート答えそう、ありがとう... – MoonKnight

+0

ちょうど下のリンクを見ました。ありがとう。 – MoonKnight

3

私はすでにMementoパターンをサポートする組み込みの方法について知らない。 .NET Mock frameworksを使用していくつかの実装を見ていますが、実際にはオブジェクトのクローンが作成され、データをフィールドに入れることができますが、それはある種のオーバーヘッドだと考えています。

通常、元に戻す/やり直し時にMementoパターンを使用します。おそらくあなたもそうです。この場合、Undo/Redoスタックのデータ量をできるだけ少なくすることをお勧めします。カスタムundoable objectは、Iのようなものです。

これが役に立ちます。

2

このパターンをC#で書くのが少し速くなるということがあります。つまり、すべての状態フィールドをpublic readonlyとして宣言できるため、プロパティにアクセスするための 'get'メソッドが不要です。

public readonlyを含むストレート変換です。

class Originator 
{ 
    private string state; 
    // The class could also contain additional data that is not part of the 
    // state saved in the memento. 

    public void Set(string state) 
    { 
     Console.WriteLine("Originator: Setting state to " + state); 
     this.state = state; 
    } 

    public Memento SaveToMemento() 
    { 
     Console.WriteLine("Originator: Saving to Memento."); 
     return new Memento(state); 
    } 

    public void RestoreFromMemento(Memento memento) 
    { 
     state = memento.SavedState; 
     Console.WriteLine("Originator: State after restoring from Memento: " + state); 
    } 

    public class Memento 
    { 
     public readonly string SavedState; 

     public Memento(string stateToSave) 
     { 
      SavedState = stateToSave; 
     } 
    } 
} 

class Caretaker 
{ 
    static void Main(string[] args) 
    { 
     List<Originator.Memento> savedStates = new List<Originator.Memento>(); 

     Originator originator = new Originator(); 
     originator.Set("State1"); 
     originator.Set("State2"); 
     savedStates.Add(originator.SaveToMemento()); 
     originator.Set("State3"); 
     // We can request multiple mementos, and choose which one to roll back to. 
     savedStates.Add(originator.SaveToMemento()); 
     originator.Set("State4"); 

     originator.RestoreFromMemento(savedStates[1]); 
    } 
} 
+0

あなたはメメント・クラスに対して正しいことを確認プライベートコンストラクタはありますか? Originatorからアクセスできますか? –

+0

あなたは正しいです!私はこれを何かコンパイルしなかったのですか?その固定今、ありがとう。 –

1

私が見つけた一つを使用してジェネリックhere

#region Originator 
public class Originator<T> 
{ 
    #region Properties 
    public T State { get; set; } 
    #endregion 
    #region Methods 
    /// <summary> 
    /// Creates a new memento to hold the current 
    /// state 
    /// </summary> 
    /// <returns>The created memento</returns> 
    public Memento<T> SaveMemento() 
    { 
     return (new Memento<T>(State)); 
    } 
    /// <summary> 
    /// Restores the state which is saved in the given memento 
    /// </summary> 
    /// <param name="memento">The given memento</param> 
    public void RestoreMemento(Memento<T> memento) 
    { 
     State = memento.State; 
    } 
    #endregion 
} 
#endregion 
#region Memento 
public class Memento<T> 
{ 
    #region Properties 
    public T State { get; private set; } 
    #endregion 
    #region Ctor 
    /// <summary> 
    /// Construct a new memento object with the 
    /// given state 
    /// </summary> 
    /// <param name="state">The given state</param> 
    public Memento(T state) 
    { 
     State = state; 
    } 
    #endregion 
} 
#endregion 
#region Caretaker 
public class Caretaker<T> 
{ 
    #region Properties 
    public Memento<T> Memento { get; set; } 
    #endregion 
} 
#endregion 
#region Originator 
public class Originator<T> 
{ 
    #region Properties 
    public T State { get; set; } 
    #endregion 
    #region Methods 
    /// <summary> 
    /// Creates a new memento to hold the current 
    /// state 
    /// </summary> 
    /// <returns>The created memento</returns> 
    public Memento<T> SaveMemento() 
    { 
     return (new Memento<T>(State)); 
    } 
    /// <summary> 
    /// Restores the state which is saved in the given memento 
    /// </summary> 
    /// <param name="memento">The given memento</param> 
    public void RestoreMemento(Memento<T> memento) 
    { 
     State = memento.State; 
    } 
    #endregion 
} 
#endregion 
#region Memento 
public class Memento<T> 
{ 
    #region Properties 
    public T State { get; private set; } 
    #endregion 
    #region Ctor 
    /// <summary> 
    /// Construct a new memento object with the 
    /// given state 
    /// </summary> 
    /// <param name="state">The given state</param> 
    public Memento(T state) 
    { 
     State = state; 
    } 
    #endregion 
} 
#endregion 
#region Caretaker 
public class Caretaker<T> 
{ 
    #region Properties 
    public Memento<T> Memento { get; set; } 
    #endregion 
} 
#endregion 

は次のように使用される:

Originator<string> org = new Originator<string>(); 
    org.State = "Old State"; 
    // Store internal state in the caretaker object 
    Caretaker<string> caretaker = new Caretaker<string>(); 
    caretaker.Memento = org.SaveMemento(); 
    Console.WriteLine("This is the old state: {0}", org.State); 
    org.State = "New state"; 
    Console.WriteLine("This is the new state: {0}", org.State); 
    // Restore saved state from the caretaker 
    org.RestoreMemento(caretaker.Memento); 
    Console.WriteLine("Old state was restored: {0}", org.State); 
    // Wait for user 
    Console.Read(); 

が@Simon SkovのBoisenはこれが唯一不変データのために働くだろう言及し、必要とするのでdeep copy

+2

私の答えを参照してください、あなたは深いコピーを考慮する必要がありますセッターのプロパティを持つ参照型を扱うとき。 –

関連する問題