Pattern: Memento

The Memento Pattern is used to capture the state of an object at a certain point in time, and to be able to restore an object to that state some time in the future.

There are three moving parts:

  1. Originator
  2. Memento
  3. Caretaker

Originator

The Originator is the object who’s state you want to record for future use; it is where the Memento originates. Typically, it is able to utilise the Memento to generate a current version of itself, and also restore a previous version of itself.

Memento

The Memento is responsible for creating an immutable copy/clone of the Originator. The copy is stored internally and the entire Memento which encapsulates it is used by the Originator and Caretaker.

Caretaker

The Caretaker is simply responsible for remembering Mementos. It is where the we go to find previous versions of objects (the Mementos), so that we can pass them back to the Originator so that previous state can be reverted to.

Flow

The Originator exposes the “create a Memento of me” and “apply a Memento of me” API which can be used to create a Memento object of the Originator.

The Memento is passed to the Caretaker. There can be multiple Mementos of an Originator being tracked by a Caretaker. The most simple application of this pattern does not require this.

At some point, a Memento is retrieved from the Caretaker and passed to the Originator, which uses the “apply a Memento of me” API to reset its internal state to that of the Memento.

Points of interest

The Memento must be immutable. When the Originator is a reference type (most likely the case), something must be done to be sure that a pointer to the original object is not all the Memento contains. We therefore need to implement some kind of cloning logic to make certain of this. I prefer JSON for this.

My version
public class CareTaker<T>
{
public Memento<T> Memento { get; private set; }

public CareTaker(Memento<T> memento)
{
Memento = memento;
}
}
public class Memento<T>
{
private string _state;

protected Memento()
{ }

public static Memento<T> Create(Originator<T> originator)
{
var mememto = new Memento<T>();
mememto.Serialize(originator);
return mememto;
}
private void Serialize(Originator<T> originator)
{
_state = JsonConvert.SerializeObject(originator);
}

public T Deserialize()
{
return JsonConvert.DeserializeObject<T>(_state);
}
}

public abstract class Originator<T>
{
public Memento<T> GenerateMemento()
{
return Memento<T>.Create(this);
}

public abstract void ApplyMemento(Memento<T> memento);
}

ApplyMemento looks like this:

public override void ApplyMemento(Memento<Product> memento)
{
var product = memento.Deserialize();
Name = product.Name;
Price = product.Price;
StockLevel = product.StockLevel;
}

[Test]
public void Mementos_Are_Resillient()
{
var product = new Product
{
Name = "Kitty cat food",
Price = 99M
};

product.PurchaseStock(); //Adds 100 Stock

var memory = new ProductCareTaker(product.GenerateMemento());
Assert.That(product.StockLevel, Is.EqualTo(100));

product.PurchaseStock();
Assert.That(product.StockLevel, Is.EqualTo(200));

product.ApplyMemento(memory.Memento);
Assert.That(product.StockLevel, Is.EqualTo(100));
}