Understanding the Memento Design Pattern in CSharp

Code Life
Why did the Originator bring a notepad to the design meeting?

Because it didn't want to forget its state and end up in an identity crisis!

The Memento Design Pattern is a behavioral design pattern that allows you to capture and externalize an object’s internal state so that the object can be restored to this state later without violating encapsulation. This pattern is particularly useful in scenarios where you need to implement undo/redo functionalities.

Key Participants

  • Originator: The object whose state needs to be saved.
  • Memento: The object that stores the state of the Originator.
  • Caretaker: The object that keeps track of multiple mementos.

Implementation in C

Let’s implement the Memento Design Pattern step by step using C#.

Step 1: Define the Memento Class

The Memento class stores the state of the Originator. It should have a minimal interface.

public class Memento
{
    public string State { get; private set; }

    public Memento(string state)
    {
        State = state;
    }
}

Step 2: Define the Originator Class

The Originator creates a memento containing its current state and uses the memento to restore its state.

public class Originator
{
    public string State { get; set; }

    public Memento SaveStateToMemento()
    {
        return new Memento(State);
    }

    public void GetStateFromMemento(Memento memento)
    {
        State = memento.State;
    }
}

Step 3: Define the Caretaker Class

The Caretaker is responsible for keeping the mementos. It can store multiple mementos to support undo/redo operations.

public class Caretaker
{
    private List<Memento> _mementoList = new List<Memento>();

    public void Add(Memento state)
    {
        _mementoList.Add(state);
    }

    public Memento Get(int index)
    {
        return _mementoList[index];
    }
}

Step 4: Putting It All Together

Now, let’s see how these classes work together to implement the Memento Design Pattern.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.State = "State #1";
        originator.State = "State #2";
        caretaker.Add(originator.SaveStateToMemento());

        originator.State = "State #3";
        caretaker.Add(originator.SaveStateToMemento());

        originator.State = "State #4";
        Console.WriteLine("Current State: " + originator.State);

        originator.GetStateFromMemento(caretaker.Get(0));
        Console.WriteLine("First saved State: " + originator.State);

        originator.GetStateFromMemento(caretaker.Get(1));
        Console.WriteLine("Second saved State: " + originator.State);
    }
}

Explanation

  1. Originator State Changes: The originator’s state changes multiple times.
  2. Saving States: States are saved using the SaveStateToMemento method and stored in the caretaker.
  3. Restoring States: The originator can restore its state using the GetStateFromMemento method.

Use Cases

The Memento Pattern is useful in several scenarios, including:

  • Undo Mechanism: Implementing undo/redo functionality in applications like text editors or drawing applications.
  • State Recovery: Restoring an object’s state in case of errors or after executing a complex operation.
  • Snapshot of State: Capturing the state of an object at a particular point in time for future reference.

The Memento Design Pattern is a powerful tool that helps manage an object’s state changes and provides mechanisms to restore previous states. By separating the concerns of saving and restoring state from the object’s core functionality, it promotes cleaner and more maintainable code. In C#, implementing this pattern involves creating Memento, Originator, and Caretaker classes, and using them to manage and restore object states efficiently.