design pattern

Behavioral Design Patterns: Memento

Moving along through our detailed Guide to Software Design Patterns series, today we land on the island of the memento design pattern. The memento pattern is typically used to store the historical state of an object and, therefore, allow previous states to be restored at any time. The pattern shares many similarities with the command pattern, which we explored in our previous Behavioral Design Patterns: Command Design Pattern post.

Throughout today’s article we’ll explore the memento design pattern by looking at both a real world example and fully-functional C# code samples. This code will illustrate how a memento pattern can be setup fairly easily, ideally providing you with some ideas for your own projects, so let’s get going!

In the Real World

The memento design pattern can be found in the real world almost everywhere we look. In fact, essentially any object you interact with that can have a singular state at a given moment in time, and which allows that state to be adjusted at will, is effectively an example of the memento pattern.

For example, consider the volume control of your television. No matter whether you have an old CRT display or a state-of-the-art smart OLED display, the fundamental behavior of changing the volume works the same. The television (or receiver, speakers, etc) has a saved volume state. If the volume is set to 3, and you can’t quite hear Morgan Freeman’s soft, dulcet tones, you’ll probably turn the knob or press your remote to crank it up to 11! The act of changing that volume state from 3 to 11 is a simple form of the memento pattern, in which we’re changing the state of an object (the volume, in this case) to a new value. Critically, we can also revert that change at any time, going back to any volume state value we had previously.

For older televisions this process will be incremental, meaning we go from 3 to 4 to 5, and so on. Yet, on some newer televisions, we can explicitly choose a value to jump to immediately, making the change from 3 to 11 in a single step. Regardless, both of these techniques are commonly used in memento design pattern implementations. In some cases, undo and redo only occur in incremental fashion, using the most recent state as the fallback position. In other cases, like the code implementation we’ll look at below, reverting to previous states can occur in any order, allowing us to jump backwards in the revision history as many jumps as required.

How It Works In Code

The memento design pattern has three key components:

  • Memento – Simple object that contains basic state storage and retrieval capabilities.
  • Originator – Gets and sets values of Mementoes. Also, creates new Mementoes and assigns current values to them.
  • Caretaker – Holds a collection that contains all previous Mementoes. Can also store and retrieve Mementoes.

As discussed in the introduction, there is a clear similarity between the memento and command patterns. The command pattern allows tasks to be assigned to a queue, which can then be processed by a client at any moment in time. This structure makes the command pattern particularly well-suited for providing undo and redo functionality, since tasks can be reverted when desired.

The memento design pattern is far more abstract, but it also allows tasks to be reverted when necessary. The distinct difference between the two patterns, however, is that the memento pattern is intended to change the singular state of just one object. On the other hand, the command pattern effectively handles multiple states simultaneously — the logic and behavior of which is handled by a Manager class that orchestrates everything. Check out our Command Design Pattern article for more details.

Alright, let’s get into the good stuff! We’ll start with the full code sample below, after which we’ll break it down in more detail to see exactly how everything is put together:

The example we’re using here is based on some of the classes we saw in our command pattern article, namely the Character class. A Character might be used as a basic entity in a video game, containing both a Name and a collection of basic attributes: Agility, Charism, and Strength. We’ll be defining generic Memento, Originator, and Caretaker classes that will all accept a generic object type <T>, which we can then specify as Characters we’ll be creating. The real world purpose of this memento pattern might be a game you’re creating in which a single Character can be selected or active at a time, but you want to retain the history of all the Characters that have been used previously, and allow the player to revert to any previous Character at will.

Our goal here is to generalize the memento pattern implementation as much as possible, so we can reuse it for future implementations if desired. Thus, we start with the Memento<T> class:

Nothing fancy going on here. All a Memento<T> object really needs is some form of state, so we’ve defined the T State property. Along with the constructor, this allows a new Memento<T> instance of any type to be created quite easily (e.g. new Memento<Character>(new Character())).

Next we have the Originator<T> class, which stores a local T _state property and updates this property based on the currently manipulated Memento<T> instance. For extensibility, we also have a simple OnMementoChanged event handler, which allows us to fire some basic logic whenever the Originator<T> instance updates a Memento<T> in some way:

The important methods of Originator<T> are CreateMemento() and SetMemento(Memento<T> memento). The former creates a new Memento<T> instance based on the current _state property, while the latter updates the _state property based on the passed Memento<T> argument.

The final piece in the memento pattern trifecta is the Caretaker<T> class:

The primary purpose of the caretaker object is to store the historical list of mementoes that have been created, effectively containing all the state values that have ever existed. The Save() method handles the creation of a new Memento<T> instance within the Originator property value. Conversely, Restore(Memento<T> memento) searches for the passed memento instance in the full list and sets the current memento (i.e. state) of Originator to that value, if its found in the list.

That’s the whole of the memento pattern setup. Now, for implementation we use the aforementioned Character class, along with the statistic classes implementing the IStatistic interface that it uses:

The Program.Main(string[] args) method actually tests all this code out for us:

As indicated by the comments, the above code starts by creating a new Originator<Character> instance, then passes that to be used by the new Caretaker<Character> instance. Next, we create a few Character instances to represent our three different characters, giving each unique names and attribute scores.

Now comes the memento pattern usage. We take our originator instance and call SetState(Memento<T> memento), passing in our first Character instance. Behind the scenes, this sets the state of the originator instance to be equal to that passed in alice Character value. Then we call caretaker.Save(), which adds the alice memento to the stored MementoList property. This also triggers our OnMementoChanged event, so we produce a little bit of output to confirm what is going on. We repeat this process a couple more times, changing the saved state first to bob, then to christine.

Finally, we call caretaker.Restore(bobMemento), which effectively checks if bob can be found in the underlying MementoList property. If so, it restores the state back to the state of when bob was added, then fires our OnMementoChanged event again to provide some output.

The result of all this code is that we should see three state changes as each Character instance is saved as the state, then a final reversion back to the state of the second bob Character. Sure enough, that’s exactly what we find in the output:

There you have it! I hope this provided a bit of insight into the potential power of the memento design pattern, and gave you some basic tools you can use in your own projects to implement it where it seems most appropriate. For more information on all the other popular design patterns, head on over to our ongoing design pattern series here!