Back to: Design Patterns in C# With Real-Time Examples
Memento Design Pattern in C# with Examples
In this article, I will discuss the Memento Design Pattern in C# with Examples. Please read our previous article discussing the Mediator Design Pattern in C# with Examples. The Memento Design Pattern falls under the category of Behavioral Design Pattern. As part of this article, we will discuss the following pointers.
- What is the Memento Design Pattern?
- Examples to Understand Memento Design Pattern.
- Understanding the Class or UML Diagram of Memento Design Pattern
- Implementation of Memento Design Pattern in C#.
- Advantages of Memento Design Pattern in C#.
- When to use Memento Design Pattern in Real-Time Applications?
What is the Memento Design Pattern?
The Memento Design Pattern is a Behavioral Design Pattern that can restore an object to its previous state. This pattern is useful for scenarios where you need to perform an undo or rollback operation in your application. The Memento pattern captures an object’s internal state so that the object can be restored to this state later. It is especially useful when implementing undo functionality in an application.
Example to Understand Memento Design Pattern:
Let us understand the Memento Design Pattern in C# with an example. Please have a look at the following image. As shown in the below image, on the left-hand side, we have an employee with Id =101, Name =John, Salary = 2Lakhs, Designation = Software Engineer, Address = London, and many more attributes. Later, we changed some of the properties, i.e., Salary to 3Lakhs and designation to Senior Software Engineer; we also changed some other employee attributes, shown on the right-hand side of the image below. That means we change the object state from State 1 to State 2.
After some time, let’s undo or roll back the employee information to its previous state, i.e., State 1. If this is your requirement, you must use the Memento Design Pattern and roll back the employee information to its previous state.
Understanding the Class or UML Diagram of Memento Design Pattern:
Let us understand the Class or UML Diagram of the Memento Design Pattern and its different components. Please look at the following image to understand the Class or UML Diagram. As you can see in the image below, three important classes (Originator, Memento, and Caretaker) are involved in the Memento Design Pattern.
So, the Roles and Responsibilities of each component are as follows:
- Originator: The Originator is a class that creates a memento object containing a snapshot of the Originator’s current state. It also restores the Originator to one of its previous states. The Originator class has two methods. One is CreateMemento, and the other one is SetMemento. The CreateMemento Method will Create a snapshot of the current state of the Originator and return that Memento, which we can store in the Caretaker for later use, i.e., for restoring purposes. The SetMemento method accepts the memento object, and this method changes the Internal State of the Originator to one of its Previous States.
- Caretaker: The Caretaker class will hold the Memento objects for later use. This class acts as a store only. It never Checks or Modifies the contents of the Memento object. This class will have two methods, i.e., AddMemento and GetMemento. The AddMomento Method will add the memento, i.e., the internal state of the Originator, into the Caretaker. The GetMemento Method returns one of the Previous Originator Internal States, saved in the Caretaker.
- Memento: The Memento class holds information about the Originator’s saved state. That means it sets the internal state and gets the internal state of the Originator object. This class has one method called GetState, which will return the Internal State of the Originator. This class also has one parameterized constructor, which you can set the internal state of the originator.
Use Cases of Memento Design Pattern:
- When you need to provide an undo mechanism in applications like text editors, graphic editors, or more complex transactional systems.
- In scenarios where you want to capture an object’s state without exposing its implementation details.
Real-Time Example to Understand Memento Design Pattern in C#:
Let us first understand the Real-Time Example that we will implement using the Memento Design Pattern in C#. I bought a 42-inch LED TV whose cost was 60000 Rupees, which does not support USB, and I placed it in the hall. After some point, I thought, let’s buy a 46-inch LED TV. So, I bought a 46-inch LED TV whose cost is 80000 Rupees, and it supports USB and I want to place it in the hall. But already in the hall, a 42-inch LED TV is there. So, what I have to do is, I have to place the 42-inch LED TV in the storeroom and place this 46-inch LED TV in the hall.
Again, after some point, I am thinking of buying a 50-inch LED TV whose cost is 100,000 Rupees, which supports USB. So, I bought this 50-inch LED TV and want to place it in the hall. But in the hall, the 46-inch LED TV is already there. So, I have to take the 46-inch LED TV from the hall, put it in the storeroom, and then place the 50-inch LED TV in the hall.
After some point, I thought, let’s put the 42-inch LED TV in the hall as the clarity of the 50-inch LED TV is not that good. So, what I do is I have to take the 50-inch LED TV from the hall and put it in the storeroom, and from the storeroom, take the 42-inch LED TV and put it in the hall. So, basically, we are rollbacking to its previous state.
In this example, the Hall is the Originator where we will store the Memento Object, and the Store Room is the Caretaker which is keeping the Memento. Led TV is the Memento, i.e., it is used to hold the internal state of LED TV. This is one of the best examples of the Memento Design Pattern. So, in a scenario like this, we need to use the Memento Design Pattern in our Real-Time Application.
Implementation of Memento Design Pattern in C#:
Let us implement the above-discussed LED TV Real-Time Example using the Memento Design Pattern in C# step by step.
Step 1: Creating LED TV
This will be our Model Class, which will hold the Product Information, i.e., the LED TV details. So, create a class file with the name LEDTV.cs and copy and paste the following code. This LED TV class has three properties (i.e., Size, Price, and USBSupport), and we are initializing these three properties using the class constructor. This class also has a method called GetDetails, which returns the details of a Led TV.
namespace MementoDesignPattern { //This is the Model class that is going to hold the Product information i.e. Led TV Details public class LEDTV { //Properties of the LED TV public string Size { get; set; } public string Price { get; set; } public bool USBSupport { get; set; } //Initializing the Properties using Constructor public LEDTV(string Size, string Price, bool USBSupport) { this.Size = Size; this.Price = Price; this.USBSupport = USBSupport; } //Fetching the Details of the LedTV public string GetDetails() { return "LEDTV [Size=" + Size + ", Price=" + Price + ", USBSupport=" + USBSupport + "]"; } } }
Step 2: Creating Memento
This will be a class that holds the information about the Originator’s saved state. This class is going to stores and returns the internal state of the Originator object. So, create a class file named Memento.cs and copy and paste the following code. Here, the LedTV is the Internal State of the Originator, and we are initializing that LedTV internal state using the Constructor. This class has one method, i.e., GetDetails, which is used to return the internal state details of the originator, i.e., LedTV. The following Memento class code is self-explained, so please go through the comment lines for a better understanding.
namespace MementoDesignPattern { //This is going to be a class that holds the information about the Originator’s saved state. //Stores the internal state of the Originator object. public class Memento { //The following Variable is going to Hold the Internal State of the Originator object public LEDTV LedTV { get; set; } //Initializing the Internal State of Originator Object using Constructor public Memento(LEDTV ledTV) { LedTV = ledTV; } //This Method is going to return the Internal State of the Originator public string GetDetails() { return "Memento [LedTV=" + LedTV.GetDetails() + "]"; } } }
Step 3: Creating Caretaker
This will be a class that is used to hold the Memento objects for later use. This class acts as a store only. It will never Check or Modify the contents of the Memento object. So, create a class named Caretaker.cs and copy and paste the following code. In our example, this is nothing but the Storeroom, where we will store the LED TVs not used in the Hall. This class has two methods. The AddMemento method is used to add a memento to the LedTvList collection property, and the GetMemento method is used to return a memento object based on the Index position. The following Caretaker class code is self-explained, so please go through the comment lines for a better understanding.
using System; using System.Collections.Generic; namespace MementoDesignPattern { //This is going to be a class that is used to hold a Memento object for later use. //This acts as a store only; it never Checks or Modifies the contents of the Memento object. public class Caretaker { //This variable is going to hold the List of Mementos that are used by the Originator. private List<Memento> LedTvList = new List<Memento>(); //This Method will add the memento i.e. the internal state of the Originator into the Caretaker i.e. Store Room public void AddMemento(Memento m) { LedTvList.Add(m); Console.WriteLine("LED TV's snapshots Maintained by CareTaker :" + m.GetDetails()); } //This Method is used to return one of the Previous Originator Internal States which saved in the Caretaker public Memento GetMemento(int index) { return LedTvList[index]; } } }
Step 4: Creating Originator
This class will create a memento object containing a snapshot of the Originator’s current state. It also provides the functionality to restore the Originator to one of its previous stored states. So, create a class file named Originator.cs and copy and paste the following code. In our example, this is the Hall where we need to place the LED TV. Here, the CreateMemento method is used to create a snapshot of the current state of the Originator, i.e., Current LedTV, and return that Memento, which we can store in the Caretaker, i.e., in the Store Room. The SetMemento method changes the Internal State of the Originator to one of its Previous States. The GetDetails method returns the Details of the Current Internal State of the Originator. The following Originator class code is self-explained, so please go through the comment lines for a better understanding.
namespace MementoDesignPattern { //This is going to be a class that creates a memento object containing a snapshot of the Originator's current state. //It also restores the Originator to a previously stored state. public class Originator { //This Property is used to store the current state of the Originator public LEDTV LedTV; //It will Create a snapshot of the current state of the Originator i.e. Current LedTV //and return that Memento which we can store in the Caretaker i.e. in the Store Room public Memento CreateMemento() { return new Memento(LedTV); } //This Method is going to change the Internal State of the Originator to one of its Previous State public void SetMemento(Memento memento) { LedTV = memento.LedTV; } //This Method is going to return the Details of the Current Internal State of the Originator public string GetDetails() { //To Fetch the Details, internally it is calling the GetDetails method on LedTV Object return "Originator [LEDTV=" + LedTV.GetDetails() + "]"; } } }
Step 5: Client
The Program class is going to be the Client in our Example. So, please modify the Main method of the Program class as shown below. The following is used to explain the Memento Design Pattern.
using System; namespace MementoDesignPattern { class Program { static void Main(string[] args) { //Creating an Instance of the Originator and setting the current state as a 42-Inch Led TV Originator originator = new Originator { LedTV = new LEDTV("42-Inch", "60000", false) }; //Storing the Internal State (Memento i.e. the Current Led TV) of the Originator in the Caretaker i.e. Store Room //First, Create an instance of the Caretaker Caretaker caretaker = new Caretaker(); //Second Create a snapshot or memento of the current internal state of the originator Memento memento = originator.CreateMemento(); //Third, store the memento or snapshot in the store room i.e. Caretaker caretaker.AddMemento(memento); //Changing the Originator Current State to 46-Inch originator.LedTV = new LEDTV("46-Inch", "80000", true); //Again storing the Internal State (Memento) of the Originator in the Caretaker i.e. Store Room //Create the memento or snapshot of the current internal state of the originator memento = originator.CreateMemento(); //Store the memento in the Caretaker caretaker.AddMemento(memento); //Again, Changing the Originator Current State to 50-Inch originator.LedTV = new LEDTV("50-Inch", "100000", true); //The Current State of the Originator is now 50-Inch Led TV Console.WriteLine("\nOrignator Current State : " + originator.GetDetails()); //Restoring the Originator to one of its previous states //We have added two Memento to the Caretaker //Index-0 means the First memento i.e. 42 Inch LED TV //Index-1 means the Second memento i.e. 46 Inch LED TV Console.WriteLine("\nOriginator Restoring to 42-Inch LED TV"); originator.SetMemento(caretaker.GetMemento(0)); Console.WriteLine("\nOrignator Current State : " + originator.GetDetails()); Console.ReadKey(); } } }
Output:
Advantages of Memento Design Pattern:
- Undo Mechanism: Provides an undo mechanism by saving the object’s previous state.
- Preserving Encapsulation: It does not violate the originator’s encapsulation, as only the originator can store and retrieve information from the memento.
- Ease of Restoration: The originator can restore its state to a previous point in time.
When to Use Memento Design Pattern in C#?
The Memento Design Pattern in C# is particularly useful in scenarios where:
- Undo Functionality: When you need to implement undo functionality in an application. The Memento pattern allows an object to save its state to be restored to this state later, effectively allowing operations to be reversed.
- Snapshot of an Object’s State: In situations where you need to take a snapshot of an object’s state at a particular point in time. This is useful in scenarios where you might need to roll back to a previous state if certain operations fail or if specific conditions are met.
- Preserving Encapsulation: If you need to preserve the encapsulation boundaries of an object while still capturing its internal state. The Memento pattern allows for capturing the internal state of an object without exposing its internal structure.
- State Save and Restore: In applications where it’s necessary to save the state of an object so that it can be restored later, such as in save-and-restore features in games or application settings.
- Transactional Operations: When implementing transactional operations where changes to objects can be committed or rolled back based on the success or failure of the transaction.
- Point-in-time Recovery: For point-in-time recovery in applications, especially where the state of objects may change frequently, and there is a need to revert to a specific state under certain conditions.
- Journaling or Auditing: In cases where you need to maintain a history of object states for auditing or journaling purposes, allowing you to track changes over time.
In the next article, I will discuss the Real-Time Examples of Memento Design Patterns in C#. In this article, I try to explain the Memento Design Pattern in C# with Examples. I hope you enjoy this Memento Design Pattern in C# with Examples article.