Memento Pattern本身似乎非常简单。我正在考虑实现与维基百科示例相同的功能,但在此之前我是否有C#的任何语言功能,以便更容易实现或使用?
答案 0 :(得分:15)
一个明显的特征是泛型,实现通用纪念品将允许您将它用于您想要的任何对象。
您将看到的许多示例将使用字符串(包括当前对此问题的回复中的所有字符串)作为状态,这是一个问题,因为它是.NET中少数几种 immutable 。
当处理可变对象(如任何带有setter-property的引用类型)时,你必须记住,当你保存纪念品时,你需要创建一个对象的深层复制。否则,每当您更改原始对象时,您都会更改纪念品。
您可以使用protobuf-net或json.net之类的序列化程序来完成此操作,因为它们不要求您使用可序列化属性标记对象,就像普通的.net序列化机制一样。
Codeproject几乎没有关于通用memento实现的文章,但他们倾向于跳过deepcopy部分:
答案 1 :(得分:3)
我不知道任何已经内置的方式来支持Memento
模式。
我通过使用.NET Mock frameworks看到了几个实现,其中实际上创建了对象的克隆并且可以是带有数据的字段,但我认为这是一种开销。
通常在Undo / Redo上使用Memento
模式,也许你也是。在这种情况下,最好尽可能减少Undo / Redo堆栈上的数据,因此自定义undoable object
是 I 所需要的。
希望这有帮助。
答案 2 :(得分:2)
有一件事可以使这种模式在C#中写得更快,也就是说任何状态字段都可以声明为public readonly
,因此您不需要属性或“获取”方法来访问它们。
这是包含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]);
}
}
答案 3 :(得分:1)
我找到了一个使用Generics 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。