C# 备忘录模式讲解和代码示例
备忘录是一种行为设计模式, 允许生成对象状态的快照并在以后将其还原。
备忘录不会影响它所处理的对象的内部结构, 也不会影响快照中保存的数据。
复杂度:
流行度:
使用示例: 备忘录的基本功能可用序列化来实现, 这在 C# 语言中很常见。 尽管备忘录不是生成对象状态快照的唯一或最有效的方法, 但它能在保护原始对象的结构不暴露给其他对象的情况下保存对象状态的备份。
概念示例
本例说明了备忘录设计模式的结构并重点回答了下面的问题:
- 它由哪些类组成?
- 这些类扮演了哪些角色?
- 模式中的各个元素会以何种方式相互关联?
Program.cs: 概念示例
using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace RefactoringGuru.DesignPatterns.Memento.Conceptual { // The Originator holds some important state that may change over time. It // also defines a method for saving the state inside a memento and another // method for restoring the state from it. class Originator { // For the sake of simplicity, the originator's state is stored inside a // single variable. private string _state; public Originator(string state) { this._state = state; Console.WriteLine("Originator: My initial state is: " + state); } // The Originator's business logic may affect its internal state. // Therefore, the client should backup the state before launching // methods of the business logic via the save() method. 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; } // Saves the current state inside a memento. public IMemento Save() { return new ConcreteMemento(this._state); } // Restores the Originator's state from a memento object. 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}"); } } // The Memento interface provides a way to retrieve the memento's metadata, // such as creation date or name. However, it doesn't expose the // Originator's state. public interface IMemento { string GetName(); string GetState(); DateTime GetDate(); } // The Concrete Memento contains the infrastructure for storing the // Originator's state. class ConcreteMemento : IMemento { private string _state; private DateTime _date; public ConcreteMemento(string state) { this._state = state; this._date = DateTime.Now; } // The Originator uses this method when restoring its state. public string GetState() { return this._state; } // The rest of the methods are used by the Caretaker to display // metadata. public string GetName() { return $"{this._date} / ({this._state.Substring(0, 9)})..."; } public DateTime GetDate() { return this._date; } } // The Caretaker doesn't depend on the Concrete Memento class. Therefore, it // doesn't have access to the originator's state, stored inside the memento. // It works with all mementos via the base Memento interface. 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()); } } } class Program { static void Main(string[] args) { // Client code. 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(); } } } Output.txt: 执行结果
Originator: My initial state is: Super-duper-super-puper-super. Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: oGyQIIatlDDWNgYYqJATTmdwnnGZQj Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: jBtMDDWogzzRJbTTmEwOOhZrjjBULe Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: exoHyyRkbuuNEXOhhArKccUmexPPHZ Caretaker: Here's the list of mementos: 12.06.2018 15:52:45 / (Super-dup...) 12.06.2018 15:52:46 / (oGyQIIatl...) 12.06.2018 15:52:46 / (jBtMDDWog...) Client: Now, let's rollback! Caretaker: Restoring state to: 12.06.2018 15:52:46 / (jBtMDDWog...) Originator: My state has changed to: jBtMDDWogzzRJbTTmEwOOhZrjjBULe Client: Once more! Caretaker: Restoring state to: 12.06.2018 15:52:46 / (oGyQIIatl...) Originator: My state has changed to: oGyQIIatlDDWNgYYqJATTmdwnnGZQj