The Memento pattern seeks to capture and externalize and object's state so that the object can be restored to this state at a later time.

The purpose of this pattern is to separate the current state of the object from a previous state, so that if something happens to the current state (it gets corrupted, it gets lost, it tries to secede from the Union) the object's state can be restored from its Memento (whether via a civil war or other, less interesting methods).

For example, let's create a memento of my current state: hungry.

var memento = someBlogger.CreateMemento(); //Hungry
someBlogger.startWriting(); //Change state to writing

Now, we can use that memento instance later to restore the state of the someBlogger object.

NOTE: This post is part of a series demonstrating software design patterns using C# and .NET.  The patterns are taken from the book Design Patterns by the Gang of Four. Check out the other posts in the series!

The Rundown

  • Type: Behavioral
  • Useful? 2/5 (Rarely)
  • Good For: Restoring an object's state from a previous state by creating a memento of said previous state.
  • Example Code: On GitHub
exceptionnotfound/DesignPatterns
Repository for all of my Daily Design Pattern posts. - exceptionnotfound/DesignPatterns
Project for this post: Memento

The Participants

  • The Memento stores internal state of the Originator object.  The Memento has no limit on what it may or may not store (e.g. as much or as little of the Originator's state as needed).
  • The Originator creates a Memento containing a "snapshot" of its internal state, and then later uses that memento to restore its internal state.
  • The Caretaker is responsible for the Memento's safekeeping, but does not operate on or examine the contents of that Memento.

A Delicious Example

Let's imagine a system in which a restaurant needs to record information about the suppliers that bring them their ingredients. For example, a really high-end restaurant might order directly from a local farm, and the restaurant needs to keep track of which ingredients come from which suppliers.

Home baking supplies
I'm sorry, did you say "free-range baking powder?" Photo by Annie Spratt / Unsplash

In our system, we need to keep track of how much information we enter about a particular supplier, and be able to restore that information to a previous state if we, say, accidentally enter the wrong address. We can demo this using the Memento pattern.

First, let's create our Originator participant, the class FoodSupplier, which will create and use Mementos:

/// <summary>
/// The Originator class, which is the class for which we want to save Mementos for its state.
/// </summary>
class FoodSupplier
{
    private string _name;
    private string _phone;
    private string _address;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            Console.WriteLine("Proprietor:  " + _name);
        }
    }

    public string Phone
    {
        get { return _phone; }
        set
        {
            _phone = value;
            Console.WriteLine("Phone Number: " + _phone);
        }
    }

    public string Address
    {
        get { return _address; }
        set
        {
            _address = value;
            Console.WriteLine("Address: " + _address);
        }
    }

    public FoodSupplierMemento SaveMemento()
    {
        Console.WriteLine("\nSaving current state\n");
        return new FoodSupplierMemento(_name, _phone, _address);
    }

    public void RestoreMemento(FoodSupplierMemento memento)
    {
        Console.WriteLine("\nRestoring previous state\n");
        Name = memento.Name;
        Phone = memento.PhoneNumber;
        Address = memento.Address;
    }
}

We also need a Memento participant, which is the FoodSupplierMemento class used by FoodSupplier:

/// <summary>
/// The Memento class
/// </summary>
class FoodSupplierMemento
{
    public string Name { get; set; }
    public string PhoneNumber { get; set; }
    public string Address { get; set; }

    public FoodSupplierMemento(string name, string phone, string address)
    {
        Name = name;
        PhoneNumber = phone;
        Address = address;
    }
}

Finally, we need our Caretaker, which stores the Mementos but never inspects or modifies them. We named this class SupplierMemory:

/// <summary>
/// The Caretaker class.  
/// This class never examines the contents of any Memento and is
/// responsible for keeping that memento.
/// </summary>
class SupplierMemory
{
    private FoodSupplierMemento _memento;

    public FoodSupplierMemento Memento
    {
        set { _memento = value; }
        get { return _memento; }
    }
}

Now, in our Main() method, we can simulate adding a new Supplier but accidentally adding the wrong address, then using the Memento to restore the old data:

static void Main(string[] args)
{
    //Here's a new supplier for our restaurant
    FoodSupplier s = new FoodSupplier();
    s.Name = "Harold Karstark";
    s.Phone = "(482) 555-1172";

    // Let's store that entry in our database.
    SupplierMemory m = new SupplierMemory();
    m.Memento = s.SaveMemento();

    // Continue changing originator
    s.Address = "548 S Main St. Nowhere, KS";

    // Crap, gotta undo that entry, I entered the wrong address
    s.RestoreMemento(m.Memento);

    Console.ReadKey();
}

Will I Ever Use This Pattern?

Maybe? I'm really not sure. I struggled for a long time to come with appropriate scenarios for this that couldn't be covered by other architectures, and eventually gave up as I simply couldn't think of one. That said, I'm happy to be wrong, so if anyone would like to give real-world examples using the Memento pattern, please feel free to share in the comments!

Summary

The Memento pattern seeks to encapsulate state of an object as another object (called a Memento) and enable the ability to restore the state of the object from that Memento.

Oh, I almost forgot something.

someBlogger.FinishWriting();
someBlogger.RestoreState(memento); //Hungry again!

Happy Coding!