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.classOriginator{// For the sake of simplicity, the originator's state is stored inside a// single variable.privatestring _state;publicOriginator(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.publicvoidDoSomething(){
Console.WriteLine("Originator: I'm doing something important.");this._state =this.GenerateRandomString(30);
Console.WriteLine($"Originator: and my state has changed to: {_state}");}privatestringGenerateRandomString(int length =10){string allowedSymbols ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";string result =string.Empty;while(length >0){
result += allowedSymbols[newRandom().Next(0, allowedSymbols.Length)];
Thread.Sleep(12);
length--;}return result;}// Saves the current state inside a memento.publicIMementoSave(){returnnewConcreteMemento(this._state);}// Restores the Originator's state from a memento object.publicvoidRestore(IMemento memento){if(!(memento is ConcreteMemento)){thrownewException("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.publicinterfaceIMemento{stringGetName();stringGetState();DateTimeGetDate();}// The Concrete Memento contains the infrastructure for storing the// Originator's state.classConcreteMemento:IMemento{privatestring _state;privateDateTime _date;publicConcreteMemento(string state){this._state = state;this._date = DateTime.Now;}// The Originator uses this method when restoring its state.publicstringGetState(){returnthis._state;}// The rest of the methods are used by the Caretaker to display// metadata.publicstringGetName(){return $"{this._date} / ({this._state.Substring(0, 9)})...";}publicDateTimeGetDate(){returnthis._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.classCaretaker{private List<IMemento> _mementos =newList<IMemento>();privateOriginator _originator =null;publicCaretaker(Originator originator){this._originator = originator;}publicvoidBackup(){
Console.WriteLine("\nCaretaker: Saving Originator's state...");this._mementos.Add(this._originator.Save());}publicvoidUndo(){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();}}publicvoidShowHistory(){
Console.WriteLine("Caretaker: Here's the list of mementos:");foreach(var memento inthis._mementos){
Console.WriteLine(memento.GetName());}}}classProgram{staticvoidMain(string[] args){// Client code.Originator originator =newOriginator("Super-duper-super-puper-super.");Caretaker caretaker =newCaretaker(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();}}}