Post

Memento Design Pattern

Memento is a behavioural design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation. This design pattern is also known as a Snapshot.

The memento pattern is implemented with three objects: 

  • An originator object.
  • A caretaker object.
  • A memento object.

The originator is some object that has an internal state. The caretaker will do something to the originator but wants to be able to undo the change. The caretaker first asks the originator for a memento object. Then it does whatever operation (or sequence of operations) it was going to do. 

To roll back to the state before the operations, it returns the memento object to the originator. The memento object itself is an opaque object (one which the caretaker cannot, or should not, change). 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace MomentoDesignPattern
{
    public interface IMemento
    {
        public string GetName();
        public string GetState();
        public DateTime GetDate();
    }

    public class Originator
    {
        private string State { get; set; }

        public Originator(string state)
        {
            State = state;

            Console.WriteLine($"Originator: Initial state is {State}");
        }

        public void ChangeState(string state)
        {
            State = state;

            Console.WriteLine();
            Console.WriteLine($"Originator: State has changed to: {State}");
        }

        public IMemento Save()
        {
            return new ConcreteMemento(State);
        }

        public void Restore(IMemento memento)
        {
            if (!(memento is ConcreteMemento))
            {
                throw new Exception("Unknown memento class " + memento.ToString());
            }

            State = memento.GetState();

            Console.WriteLine($"Originator: State has changed to: {State}");
        }
    }

    public class Caretaker
    {
        private List<IMemento> _mementos = new List<IMemento>();
        private Originator _originator = null;

        public Caretaker(Originator originator)
        {
            _originator = originator;
        }

        public void Save()
        {
            var milliseconds = 1000;

            _mementos.Add(this._originator.Save());

            Console.WriteLine("Caretaker: Saving originator's state");
            Thread.Sleep(milliseconds);
        }

        public void Undo()
        {
            if (_mementos.Count == 0)
            {
                return;
            }

            var memento = _mementos.Last();
            _mementos.Remove(memento);

            Console.WriteLine();
            Console.WriteLine("Caretaker: Undo originator's state");

            try
            {
                _originator.Restore(memento);
            }
            catch (Exception)
            {
                Undo();
            }
        }

        public void ShowHistory()
        {
            Console.WriteLine();
            Console.WriteLine("Caretaker: History:");

            foreach (var memento in _mementos)
            {
                Console.WriteLine(memento.GetName());
            }
        }
    }

    public class ConcreteMemento : IMemento
    {
        private string State { get; set; }
        private DateTime Date { get; set; }

        public ConcreteMemento(string state)
        {
            State = state;
            Date = DateTime.Now;
        }

        public string GetState() =>
            State;


        public string GetName() =>
            $"{Date} - {State}";


        public DateTime GetDate() =>
            Date;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Momento Design Pattern");
            Console.WriteLine("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.");
            Console.WriteLine();

            Originator originator = new Originator("Alpha");
            Caretaker caretaker = new Caretaker(originator);
            caretaker.Save();

            originator.ChangeState("Beta");
            caretaker.Save();

            originator.ChangeState("Gamma");
            caretaker.Save();

            originator.ChangeState("Delta");

            caretaker.ShowHistory();

            caretaker.Undo();
            caretaker.Undo();
            caretaker.Undo();

            Console.WriteLine();
        }
    }
}

What is a Design Pattern?

In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design.