设计模式之备忘录模式
备忘录模式
概念
Memento is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation.
备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
场景
在支持 Undo/Redo 的场景下面,如果需要撤销某一次行为的时候,在执行行为之前需要将数据保存下来。
备忘录模式指的是专门构造一个类似Snapshot的类,保存当时的一些数据信息,这些信息不能修改。
在撤销的时候,拿出来这些数据,以便恢复现场。
案例
首先实现记录现场的数据类,主要记录了当时的时间和文本
public interface IMemento { string GetName(); string GetState(); DateTime GetDate(); } class ConcreteMemento : IMemento { private string _state; private DateTime _date; public ConcreteMemento(string state) { this._state = state; this._date = DateTime.Now; } public string GetState() { return this._state; } public string GetName() { return $"{this._date} / ({this._state.Substring(0, 9)})..."; } public DateTime GetDate() { return this._date; } }
接着负责行为的类,会在恰当的时机,保存现场,生成这样一个对象
class Originator { private string _state; public Originator(string state) { this._state = state; Console.WriteLine("Originator: My initial state is: " + state); } public void DoSomething() { Console.WriteLine("Originator: I'm doing something important."); this._state = this.GenerateRandomString(30); Console.WriteLine($"Originator: and my state has changed to: {_state}"); } private string GenerateRandomString(int length = 10) { string allowedSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; string result = string.Empty; while (length > 0) { result += allowedSymbols[new Random().Next(0, allowedSymbols.Length)]; Thread.Sleep(12); length--; } return result; } public IMemento Save() { return new ConcreteMemento(this._state); } public void Restore(IMemento memento) { if (!(memento is ConcreteMemento)) { throw new Exception("Unknown memento class " + memento.ToString()); } this._state = memento.GetState(); Console.Write($"Originator: My state has changed to: {_state}"); } }
然后实现Undo的manager类会把每一步行为都保存
class Caretaker { private List<IMemento> _mementos = new List<IMemento>(); private Originator _originator = null; public Caretaker(Originator originator) { this._originator = originator; } public void Backup() { Console.WriteLine("\nCaretaker: Saving Originator's state..."); this._mementos.Add(this._originator.Save()); } public void Undo() { if (this._mementos.Count == 0) { return; } var memento = this._mementos.Last(); this._mementos.Remove(memento); Console.WriteLine("Caretaker: Restoring state to: " + memento.GetName()); try { this._originator.Restore(memento); } catch (Exception) { this.Undo(); } } public void ShowHistory() { Console.WriteLine("Caretaker: Here's the list of mementos:"); foreach (var memento in this._mementos) { Console.WriteLine(memento.GetName()); } } }
最终调用如下:
Originator originator = new Originator("Super-duper-super-puper-super."); Caretaker caretaker = new Caretaker(originator); caretaker.Backup(); originator.DoSomething(); caretaker.Backup(); originator.DoSomething(); caretaker.Backup(); originator.DoSomething(); Console.WriteLine(); caretaker.ShowHistory(); Console.WriteLine("\nClient: Now, let's rollback!\n"); caretaker.Undo(); Console.WriteLine("\n\nClient: Once more!\n"); caretaker.Undo(); Console.WriteLine();