A Picture Is Worth A Thousand Words - Memento Design Pattern

The word Memento means - an object kept as a reminder of a person or event.
 
Memento is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation. The below image depicts the players. The Class whose lifecycle is to be tracked and a repository (in-memory) of the snapshots of the object of this class which holds the data at a particular spot on the timeline. One invisible player in the below image is the one who will control and decide when to take these snapshots and restore them.
A Picture Is Worth A Thousand Words - Memento Design Pattern
You may have read numerous articles and explanations on Memento Design Pattern. Here, I am trying to explain it by using more pictures and fewer words. Let's say I have a paint editor canvas application where I am trying to draw the following image,
 A Picture Is Worth A Thousand Words - Memento Design Pattern
Now, I have used a number of geometric figures to create this image.
A Picture Is Worth A Thousand Words - Memento Design Pattern
 
Underlying each shape, there is the number of properties of the shapes that hold their 'state'. The word 'state' here means all details related to the shape - its coordinates, color, size, border color, etc.
A Picture Is Worth A Thousand Words - Memento Design Pattern
Now let's explore my expectation from the application,
  1. I should be able to add any shape to the canvas.
  2. I should be able to change its size and move it around.
  3. I should be able to UNDO if I feel that I don't like what I added or changed.
  4. The system should keep saving my changes so that I can restore them.
Here is the overall expectation in the form of a picture.
A Picture Is Worth A Thousand Words - Memento Design Pattern
 
Whenever the user (you / I ), make any change on the canvas, the Editor tells that event to the caretaker. The caretaker / Manager then immediately takes a backup (snapshot) of the current state of the editor and stores it in the snapshot buckets. The Bucket List is maintained by the Caretaker only. When and which bucket to restore or delete, it is managed by the Caretaker. 
 
Few points to understand the function of each of the players here - The Editor, the Caretaker, and the Snapshot Buckets.
 
The Caretaker does not know what is inside the snapshot - what attributes, how many attributes, etc. Only the Editor knows, what it is saving in the bucket. Thus the details are completely 'encapsulated' between Editor and Bucket. The Caretaker only controls when to take a backup and when to restore it, that's it. This allows the programmer to implement different capabilities of the Caretaker without burdening it with inner details.
 
In terms of OOPS, the class structure for these players would typically be, 
A Picture Is Worth A Thousand Words - Memento Design Pattern
 
The actions would work like this,
A Picture Is Worth A Thousand Words - Memento Design Pattern 
Finally, if you wish you have the classes in the form of code, here is the snippet, 
  1. using System.Collections.Generic;  
  2. using System.Linq;  
  3. namespace MementoExample {  
  4.     public class Color {  
  5.         //Properties of R,G,B values    
  6.     }  
  7.     public class EndPointCoordinates {  
  8.         //Properties of X, Y    
  9.     }  
  10.     public class SnapShot {  
  11.         public string ShapeName {  
  12.             get;  
  13.             set;  
  14.         }  
  15.         /// All the end point cursors collection, dependending on    
  16.         /// how many corners the shape has.    
  17.         public List < EndPointCoordinates > Cursors {  
  18.             get;  
  19.             set;  
  20.         }  
  21.         public Color FillColor {  
  22.             get;  
  23.             set;  
  24.         }  
  25.         public Color BorderColor {  
  26.             get;  
  27.             set;  
  28.         }  
  29.         /// Constructor    
  30.         public SnapShot(Color fill, Color border, List < EndPointCoordinates > coordinates) {}  
  31.     }  
  32.     // The originator holds some important data that may change over    
  33.     // time. It also defines a method for saving its state inside a    
  34.     // memento and another method for restoring the state from it.    
  35.     public class Originator {  
  36.         public List < EndPointCoordinates > CurrentCoordinates {  
  37.             private get;  
  38.             set;  
  39.         }  
  40.         public Color FillColor {  
  41.             private get;  
  42.             set;  
  43.         }  
  44.         public Color BorderColor {  
  45.             private get;  
  46.             set;  
  47.         }  
  48.         // Saves the current state inside a memento.    
  49.         public SnapShot CreateSnapshot() {  
  50.             return new SnapShot(fill: FillColor, border: BorderColor, coordinates: CurrentCoordinates);  
  51.         }  
  52.         public void RestoreSnapshot(SnapShot snapshot) {  
  53.             CurrentCoordinates = snapshot.Cursors;  
  54.             FillColor = snapshot.FillColor;  
  55.             BorderColor = snapshot.BorderColor;  
  56.         }  
  57.     }  
  58.     public class CareTaker {  
  59.         readonly Originator editor = new Originator(); // clean slate    
  60.         readonly List < SnapShot > backupStack = new List < SnapShot > (); // the snapshot collection    
  61.         public void makeBackup() {  
  62.             backupStack.Add(editor.CreateSnapshot());  
  63.         }  
  64.         public void Undo() {  
  65.             editor.RestoreSnapshot(backupStack.Last()); //restore the last added snapshot    
  66.             backupStack.RemoveAt(backupStack.Count - 1);  
  67.             //delete the snapshot after restoring it    
  68.             //however this is optional. You can retain this snapshot if you wish to implement REDO    
  69.         }  
  70.     }  
  71. }  
Now some real-world, programming tip.
 

Conclusion 

  1. The Originator class can produce snapshots of its own state, as well as restore its state from snapshots when needed.
  2. The Memento is a value object that acts as a snapshot of the originator’s state. It’s a common practice to make the memento immutable and pass it the data only once, via the constructor.
  3. The Caretaker knows not only “when” and “why” to capture the originator’s state, but also when the state should be restored.
  4. Though I have shown here as a public class, in the practical implementation, the memento (Snapshot) class is nested inside the originator (C# allows nested classes). This lets the originator access the fields and methods of the memento, even though they’re declared private. On the other hand, the caretaker has very limited access to the memento’s fields and methods, which lets it store mementos in a stack but not tamper with their state. Since the memento class doesn’t declare any public fields, getters, or setters. Therefore no object can alter its contents. Mementos are linked to the Originator object that created them. This lets a memento restore the linked Originator’s state bypassing the data via setters on the Originator object. Since mementos are linked to specific Originator objects, you can make your app support several independent Originator types with a centralized Caretaker stack.
Watch out for,
  1. Determine what class will play the role of the originator. It’s important to know whether the program uses one central object of this type or multiple smaller ones.
  2. Make the memento class immutable. A memento should accept the data just once, via the constructor. The class should have no setters.
  3. The app might consume lots of RAM if clients create mementos too often.
  4. Caretakers should track the originator’s lifecycle to be able to destroy obsolete mementos. The caretaker, whether it represents a command object, a history, or something entirely different, should know when to request new mementos from the originator, how to store them and when to restore the originator with a particular memento.

Next Recommended Reading C# Corner Webinar on Design Pattern