The post The Memento Pattern in C# – How to Achieve Effortless State Restoration appeared first on Dev Leader.
The Memento Pattern is a software design pattern that is used to save and restore objects to their original states. The purpose of the Memento Pattern is to enable effortless restoration of an object’s previous state. In this article, we’ll be looking at the Memento Pattern in C# with code examples.
In software engineering, state restoration is the ability to bring back the previous states of an object or system. This is important because it helps prevent system crashes and loss of data. With the Memento Pattern in C#, developers can implement state restoration without much effort. This design pattern is particularly useful when building applications that need to track changes to an object over time.
By following the steps outlined in this article, C# developers can easily implement the Memento Pattern in their C# projects.
How the Memento Pattern Works
The Memento Pattern is a software design pattern that allows developers to restore an object’s previous state with ease. It is often used in undo-redo systems or situations requiring state restoration — and we’re all familiar with pressing ctrl+Z to get our work back! It works by separating an object’s state and creating a memento object that stores the state. This memento object can later be returned to restore the object’s previous state.
Origin and Principle of the Memento Pattern
Design patterns are generally classified into three categories: behavioral, creational, and structural patterns. The Memento Pattern falls under the behavioral pattern category. It was first introduced by the GoF (Gang of Four) in their book “Design Patterns: Elements of Reusable Object-Oriented Software” (affiliate link).
The principle of the Memento Pattern is to save and restore an object’s previous state without exposing its private implementation. This pattern ensures encapsulation and separation of concerns by separating an object’s state from the object itself. This way, the object’s state can be retrieved and restored without compromising its integrity.
Different Components of the Memento Pattern in C
The primary components of the Memento Pattern in C# include the Memento, Originator, Details, and Caretaker. The Memento object stores the object’s state, while the Originator creates and restores the object’s state. Details provide a snapshot of the object state, and Caretaker is responsible for the object’s history.
The Memento object captures and saves the current state of the Originator object. The Originator object creates a new Memento object and saves its state in the Memento object. The Details object is used to provide a snapshot of the object state. Caretaker is responsible for saving and restoring the object’s state history. We’ll see this in more detail by looking at some code momentarily!
Examples of the Memento Pattern
One use case example for the Memento Pattern is for a game that allows the save and load of levels. A game level can be designed as an object, and its state, including objects placed, scores gained, and player location, can be captured and saved in a Memento object. The system can later load and restore the saved level state.
Another example of where the Memento Pattern can be applied is in a text editor system (just like the code editor you use daily). In such a system, users can perform undo and redo operations after typing. The Memento Pattern can be used to store a snapshot of the text area’s state. When an undo operation is performed, the text area can be restored to its previous state, as stored in the memento.
Get your copy of my Design Patterns E-Book!
Steps to Implement Memento Pattern in C
Creating the Originator Class
The first step is to create the Originator class, which is responsible for creating and restoring an object’s state. The Originator class needs to have a method that returns a Memento object containing the current state of the object.
To create an Originator class, you’ll first need to define the state you want to save as properties. Then, you’ll need to create a method that returns a new Memento object with the current state. This method should save the current state of the properties in a new Memento object.
Below is an example of a simple Originator class that saves and restores a string property:
public class TextEditor
{
private string text;
public string Text
{
get => text;
set
{
text = value;
Save();
}
}
private void Save()
{
Console.WriteLine($"Saving state: {text}");
}
public TextEditorMemento CreateMemento() => new TextEditorMemento(text);
public void Restore(TextEditorMemento memento)
{
text = memento.Text;
Console.WriteLine($"State restored: {text}");
}
public class TextEditorMemento
{
public string Text { get; private set; }
public TextEditorMemento(string text)
{
Text = text;
}
}
}
The Memento Class
The next step in implementing the Memento Pattern is creating a Memento class. The Memento class stores the state of the Originator object and provides access to that state when the object’s state needs to be restored.
To create a Memento class, you’ll need to define the state you want to save as properties. Then, you’ll need to create a constructor that takes in the object’s current state and sets the state properties.
Below is an example of a simple Memento class for our TextEditor:
public class TextEditorMemento
{
public string Text { get; private set; }
public TextEditorMemento(string text)
{
Text = text;
}
}
The Caretaker Class
The third step in implementing the Memento Pattern is creating the Caretaker class. The Caretaker class is responsible for storing and managing the Memento objects that hold the Originator object’s state. It provides an interface for saving and restoring the object state.
To create a Caretaker class, you’ll need to define a list for storing the Memento objects. Then, you’ll need to create methods for adding Mementos to the list and retrieving Mementos from the list.
Here’s a simple Caretaker class for our TextEditor example:
public class TextEditorHistory
{
private readonly List<TextEditorMemento> _mementos = new List<TextEditorMemento>();
public void Save(TextEditorMemento memento)
{
_mementos.Add(memento);
Console.WriteLine($"Editor state saved: {memento.Text}");
}
public TextEditorMemento Undo()
{
var memento = _mementos.LastOrDefault();
if (memento != null)
{
_mementos.Remove(memento);
Console.WriteLine($"Editor state restored: {memento.Text}");
}
return memento;
}
}
Adding Undo Functionality
The final step is to add ‘Undo’ functionality. When ‘Undo’ is performed, the latest Memento object is retrieved from the Caretaker object and used to restore the object’s state. The Originator object is updated with the restored state.
To add ‘Undo’ functionality, you’ll need to modify the Originator class to include a method that restores the object’s state from a Memento object. Then, you’ll need to modify the Caretaker class to keep track of a history of Mementos so that the application can undo changes.
Here’s an example of a simple ‘Undo’ implementation for our TextEditor example:
var textEditor = new TextEditor();
var history = new TextEditorHistory();
textEditor.Text = "hello";
history.Save(textEditor.CreateMemento());
textEditor.Text = "world";
history.Save(textEditor.CreateMemento());
textEditor.Restore(history.Undo()); // Restores state to "hello"
Benefits and Tradeoffs
Benefits of the Memento Pattern in C
Implementing the Memento Pattern in C# can bring several benefits to your code. First, it can simplify the application’s state restoration process. The Memento Pattern allows objects to be restored to their previous state with minimal complexity or interference. It can also improve an application’s scalability and flexibility since it separates an object’s state and its implementation.
Another benefit is that it can improve the code’s readability and maintainability by organizing the necessary code into separate components. The Memento Pattern meets the ‘Single Responsibility Principle’ and encapsulates all of the necessary information regarding the object’s state. Compared to some other design patterns, the Memento Pattern is more maintainable, scalable, and flexible.
Drawbacks of the Memento Pattern in C
Like any other software design pattern, the Memento Pattern has drawbacks. Implementing the pattern requires an increase in memory since the Memento objects use more memory to store states. This increase can pile up, resulting in performance degradation — So you need to be careful when managing state. It might be a good opportunity for some tests!
In addition, Memento Pattern can overcomplicate simple applications. When deciding whether to use the Memento Pattern or another software design pattern, it is essential to consider the application’s use case. The Memento Pattern is most useful when an object or application undergoes frequent state changes. The pattern would not be recommended for systems with minimal state changes.
In general, the Memento Pattern is an excellent software design pattern that can bring valuable benefits to your code. It can also help an application scale by separating the aspects of state management from an object’s implementation. Still, before implementation, it is essential to consider the tradeoffs and how it can affect the application’s overall performance.
Wrapping Up The Memento Pattern in C
In this article, I discussed the Memento Pattern in C# and how it can be used to restore the state of an object effortlessly. We covered the origin and principle of the Memento Pattern and explained its different components, including the Memento, Originator, Details, and CareTaker classes.
I also provided a detailed explanation of the steps required to implement the Memento Pattern in C#, including creating an Originator class, a Memento class, and a Caretaker class. I also discussed how to add ‘Undo’ functionality to the pattern and the benefits and tradeoffs of implementing it in your programs.
In conclusion, using the Memento Pattern in C# can lead to easy state restoration and provide a cleaner, more organized codebase. If you’re interested in more learning opportunities, subscribe to my free weekly newsletter and check out my YouTube channel!
Want More Dev Leader Content?
- Follow along on this platform if you haven’t already!
- Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: SUBSCRIBE FOR FREE
- Looking for courses? Check out my offerings: VIEW COURSES
- E-Books & other resources: VIEW RESOURCES
- Watch hundreds of full-length videos on my YouTube channel: VISIT CHANNEL
- Visit my website for hundreds of articles on various software engineering topics (including code snippets): VISIT WEBSITE
- Check out the repository with many code examples from my articles and videos on GitHub: VIEW REPOSITORY
Top comments (0)