The Memento pattern provides you with the ability to restore an object to its previous state (undo by rollback).
The Memento pattern can have different purposes, but above all is known as the Undo Pattern. If you are mentally in an object oriented mood you could ask yourself…
Why on earth and above want they to put the internal data outside of the class in question? That’s not data hiding, is it?
… but the truth is that memento pattern doesn’t violate encapsulation of the internal state.
As a consequence, this pattern can come very handy when you want to store its internal state and reclaim it later without knowledge of the original object.
The client creates an originator object, which has a certain internal state. This can be any object, of course. The important objects are the caretaker and memento. A memento is created by the originator and stored in the caretaker. At a later point in time the previous state can be restored by setting the originators memento to the caretaker’s stored memento.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Client { public static void Run() { Originator originator = new Originator(); originator.State = "First state"; // a memento is created and stored Caretaker caretaker = new Caretaker(); caretaker.Memento = originator.CreateMemento(); // change the internal state of the originator object originator.State = "Second state"; Console.WriteLine("Restoring previous state."); originator.SetMemento(caretaker.Memento); } } |
The originator object can be any object, as long as they implement a CreateMemento and SetMemento method. The CreateMemento method should return a filled memento object, whilst the SetMemento should read the data stored in the memento and restore its internal state.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Originator { private string m_State; public string State { get { return m_State; } set { m_State = value; Console.WriteLine("current state = {0}", m_State); } } public Memento CreateMemento() { return (new Memento(State)); } public void SetMemento(Memento memento) { State = memento.State; } } |
The Memento object contains the originators internal state, so must have a similar structure. To design a Memento class you could start with a copy of the originator class and strip all unnecessary methods and attributes.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Memento { private string m_State; public Memento(string state) { this.m_State = state; } public string State { get { return m_State; } } } |
The Caretaker only contains the memento. In this example there is just one memento, but normally the caretaker contains a list of mementos.
|
1 2 3 4 5 |
class Caretaker { public Memento Memento; } |
And of course, you can click here for a simplified
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; enum ArticleStatus { Draft, PendingReview, Published } class Client { static void Run(string[] args) { // initial state Article article = new Article(); article.Status = ArticleStatus.Draft; // save state StatusStore store = new StatusStore(); store.StoredStatus = article.CreateStoredStatus(); // user pressed the publish button article.Status = ArticleStatus.Published; article.Save(); // user presse the undo button article.RestoreToPreviousState(store.StoredStatus); article.Save(); } } class Article { private ArticleStatus m_State; public ArticleStatus Status { get { return m_State; } set { m_State = value; } } public void Save() { // persisting logic } public ArticleState CreateStoredStatus() { return (new ArticleState(Status)); } public void RestoreToPreviousState(ArticleState memento) { Status = memento.State; } } class ArticleState { private ArticleStatus m_State; public ArticleState(ArticleStatus state) { this.m_State = state; } public ArticleStatus State { get { return m_State; } } } class StatusStore { public ArticleState StoredStatus; } |
This post is part of my series on the foundational design patterns in C#. In this series I explore the ancient design patterns and their use in real-world programming situations of today. In these series of posts we explore each pattern by looking at a minimalistic example to reveal its structure and then look at more concrete and useful real-world C# code that implements the pattern.
Comments