Memento Design Pattern in C# with Example

1. Definition

The Memento Design Pattern provides a way to capture an object's internal state so that it can be restored to that state at a later time. This is mainly used for implementing features like "undo".

2. Problem Statement

Consider a text editor application. Users often make changes to their text and might decide they want to undo a series of changes. Implementing such an "undo" functionality can be challenging without causing tight coupling between the application's classes.

3. Solution

The Memento pattern involves three main components:

1. Originator - The class for which the state needs to be saved and restored.

2. Memento - The class that stores the state of the Originator.

3. Caretaker - The class that keeps track of multiple memento states.

Using these components, the application can save and restore the Originator's state without violating its encapsulation.

4. Real-World Use Cases

1. Undo and redo functionality in software applications.

2. Snapshots of system configurations.

3. Saving game states in video games.

5. Implementation Steps

1. Define the Memento class that will store the state of the Originator.

2. Implement the Originator class which creates the Memento and sets its state.

3. Use a Caretaker class to manage, store, and retrieve mementos.

6. Implementation in C#

// Memento class
public class Memento
{
    public string State { get; private set; }
    public Memento(string state)
    {
        State = state;
    }
}

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

    // Creates memento and saves the state
    public Memento CreateMemento()
    {
        return new Memento(State);
    }

    // Restores the state from the memento
    public void SetMemento(Memento memento)
    {
        State = memento.State;
    }
}

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

    public void AddMemento(Memento memento)
    {
        _mementoList.Add(memento);
    }

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

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

        // Set and save state
        originator.State = "State1";
        caretaker.AddMemento(originator.CreateMemento());

        originator.State = "State2";
        caretaker.AddMemento(originator.CreateMemento());

        // Restore state to the first saved state
        originator.SetMemento(caretaker.GetMemento(0));

        Console.WriteLine("Restored State: " + originator.State);
    }
}

Output:

Restored State: State1

Explanation:

In this example, the Originator sets its state and uses the Caretaker to save these states as mementos. Later, the Originator restores its state using a saved memento. This allows us to "go back in time" and retrieve past states without compromising the internal details of the Originator.

7. When to use?

1. Use the Memento pattern when you want to produce snapshots of an object's state to be able to restore a previous state of the object.

2. The pattern can be used when direct access to such operations within an object violates its privacy rules or when the object doesn't have a defined interface, but you still need to interact with its state.


Comments