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));
}

Instruqt: Events

Nuts and Bolts

Events are the formalisation of the subscriber / publisher pattern we see when multicasting delegates. We have the invoker of the delegate, the “publisher”, and all the target methods which are executed, the “subscribers”.

We could stick with delegates to achieve the desired results, but the fact that subscribers can interfere with one another prevents this from being a great solution. Subscribers could reset the delegate by setting it to null, thereby removing all subscribers, and they could remove specific subscribers by using the -= operator.

Events exist to prevent subscribers from interfering with one another. This is achieved by wrapping delegate functionality to make available only the subset of functionality required to support the publisher / subscriber model.

Events are declared as follows:

public class Broadcaster {
    public event NotifyThingy Notifyer; 
}

In the above declaration, NotifyThingy would be a delegate, declared within scope as follows:

public delegate void NotifyThingy(string message);

So it’s clear from the example above that delegates are driving the event implementation, which makes sense as events are just a wrapper as mentioned before.

The Standard Event Pattern

A standard pattern exists for event implementations which completes the formalisation of the pub/sub model. The pattern exists of three parts:

  1. The event declaration
  2. An EventArgs implementation for conveying information within the event
  3. A function to wrap event invocation by the publisher

Here is an example:

public class Stock {
    public EventHandler<PriceChangedEventArgs> PriceChanged;

    protected virtual void OnPriceChanged(int oldPrice, int newPrice) {
      if (PriceChanged != null)
        PriceChanged(this, new PriceChangedEventArgs(oldPrice, newPrice, Symbol));
    }

    public readonly string Symbol;

    public Stock(string symbol) {
      Symbol = symbol;
    }

    public int Price {
      get { return _price; }
      set {
        if (_price != value)
          OnPriceChanged(_price, value);

        _price = value;
      }
    }
}

public class PriceChangedEventArgs : EventArgs {
  public readonly int OldPrice;
  public readonly int NewPrice;
  public readonly string Symbol;

  public PriceChangedEventArgs(int oldPrice, int newPrice, string symbol) {
    OldPrice = oldPrice;
    NewPrice = newPrice;
    Symbol = symbol;
  }
}

A few things to take notice of:

  1. The generic EventHandler<T> delegate
  2. The fact that the invocation wrapper function is protected virtual, meaning subclasses can fire the event, and execute code before and after the event.
  3. The null check in the event invocation wrapper function

The EventHandler<T> delegate means we can forgo the need to declare an underlying delegate explicitly for our events. A non-generic EventHander delegate also exists for when we don’t need to pass anything in the event.

 

Instruqt: Delegates

Nuts and bolts

A Delegate is a type which represents a function pointer, and as such it enables you to dynamically wire up a method caller to the target method. It literally delegates a method call from the delegate to the target method(s).

A Delegate Type defines the delegate protocol, or method signature of the target methods:

delegate int NumberCruncher(int a, int b);

a Delegate Instance represents a method which matches the protocol and has been associated with the delegate:

NumberCruncher multiplier = MultiplyNumbers;

private int MultiplyNumbers(int a, int b) {
    return a*b;
}

All delegates have multicast capabilities (as they implicitly inherit from System.MulticastDelegate), meaning that multiple target methods can be associated to a single delegate, or more correctly, multiple methods can be associated to a delegate instance. This is achieved by using the += operator:

multiplier += AddNumbers;

private int AddNumbers(int a, int b) {
    return a+b;
}

Invoking the delegate will result in all the associated methods executing in the order in which they were added. If the delegate has a return value, only the return value of the last method will the returned, with all other return values discarded.

Removing a method from the list of target methods is done by using the -= operator. The += and -= operators are compiled to the static Combine and Remove methods of the Delegate class.

Plugin Methods

Delegates are handy for plugging dynamic functionality into another method:

public void PerformANumericDuty(int[] values, NumberCruncher cruncher) {
    //do something here...    

    for(int i = 0; i < values.Length; i++)
        values[i] = cruncher(values[i], 10)
    }
}

Generic Delegates

Delegates may use generic type parameters:

delegate T GenericDelegate<T>(T arg);

GenericDelegate<double> squarer = Square;

private double Square(double a){
    return a*a;
}

Contravariance

Delegates are contravariant, meaning that the delegate type parameters can be more specific than the delegate instance type parameters:

class House : Asset { ... }

delegate void SellHouse(House house);

...

private void SellAsset(Asset asset){ ... }

...

SellHouse houseSeller = SellAsset;

...

houseSeller(new House());

Covariance

Delegates are covariant, meaning that the return type of a delegate type can be less specific than the return type of the delegate instance.

class House : Asset { ... }

delegate Asset GetAsset();

...

GetAsset getMyHouse = GetHouse();

...

private House GetHouse() { ... }

...

Asset myhouse = getMyHouse();