如何在C#4中实现Memento模式?

Memento Pattern本身看起来非常简单。 我正在考虑实现与维基百科示例相同的function,但在此之前我是否有C#的任何语言function,以便更容易实现或使用?

一个显而易见的function是generics,实现通用纪念品将允许您将它用于您想要的任何对象。

您将看到的许多示例将使用字符串(包括当前对此问题的回复中的所有字符串)作为状态,这是一个问题,因为它是.NET中为数不多的几种类型之一。

处理可变对象(如任何具有setter-property的引用类型)时,您必须记住,当您保存纪念品时,您需要创建对象的深层复制。 否则,每当您更改原始对象时,您都会更改纪念品。

您可以通过使用像protobuf-net或json.net这样的序列化程序来完成此操作,因为它们不需要您使用可序列化属性来标记您的对象,就像普通的.net序列化机制一样。

Codeproject几乎没有关于通用memento实现的文章,但他们倾向于跳过deepcopy部分:

C#中撤销重做的通用纪念模式

纪念品设计模式

我不知道任何已经内置的方式来支持Memento模式。 我通过使用.NET Mock框架看到了几个实现,其中实际上创建了对象的克隆并且可以使用数据进行字段化,但我认为这是一种开销。

通常在Undo / Redo上使用Memento模式,也许你也是。 在这种情况下,最好尽可能减少Undo / Redo堆栈上的数据,因此自定义可撤销undoable object想要的。

希望这可以帮助。

有一点可以使这种模式在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 savedStates = new List(); 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]); } } 

我在这里找到了一个使用Generics的人:

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

像这样使用:

  Originator org = new Originator(); org.State = "Old State"; // Store internal state in the caretaker object Caretaker caretaker = new Caretaker(); 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所提到的,这只适用于不可变数据,需要深层复制 。