Memento Pattern | Behavioral Design Pattern

Memento Pattern 

The Memento Pattern is a behavioral design pattern that allows an object's state to be captured and restored later. This is useful for implementing undo functionality or maintaining a history of changes. 

The Memento Pattern involves three key components:


1. Originator:

   - Represents the object whose state needs to be saved.

   - Has a method to create a memento containing its current state.

   - Has a method to restore its state from a given memento.


2. Memento:

   - Represents the object that stores the state of the Originator.

   - Should have methods to get and set the state.


3. Caretaker:

   - Keeps track of multiple mementos, usually in a list.

   - Responsible for storing and retrieving mementos.


Example in C#:

using System;

using System.Collections.Generic;


// Originator

class TextEditor

{

    private string text;


    public string Text

    {

        get => text;

        set

        {

            Console.WriteLine("Updating text: " + value);

            text = value;

        }

    }


    public EditorMemento Save()

    {

        Console.WriteLine("Saving state...");

        return new EditorMemento(text);

    }


    public void Restore(EditorMemento memento)

    {

        Console.WriteLine("Restoring state...");

        text = memento.Text;

    }

}


// Memento

class EditorMemento

{

    public string Text { get; }


    public EditorMemento(string text)

    {

        Text = text;

    }

}


// Caretaker

class HistoryManager

{

    private readonly Stack<EditorMemento> history = new Stack<EditorMemento>();


    public void SaveState(EditorMemento memento)

    {

        history.Push(memento);

    }


    public EditorMemento Undo()

    {

        Console.WriteLine("Undoing...");

        return history.Pop();

    }

}


// Example Usage

class Program

{

    static void Main()

    {

        TextEditor editor = new TextEditor();

        HistoryManager historyManager = new HistoryManager();


        // User makes changes

        editor.Text = "First line";

        historyManager.SaveState(editor.Save());


        editor.Text = "Second line";

        historyManager.SaveState(editor.Save());


        // Undo to previous state

        EditorMemento previousState = historyManager.Undo();

        editor.Restore(previousState);


        Console.WriteLine("Current text: " + editor.Text);

    }

}

In this example, the TextEditor is the originator, EditorMemento is the memento, and HistoryManager is the caretaker. Users can make changes to the text, and the HistoryManager keeps track of the states using mementos, allowing users to undo changes and revert to previous states.


Redo functionality in the context of the Memento Pattern.

using System;

using System.Collections.Generic;


// Originator

class TextEditor

{

    private string text;


    public string Text

    {

        get => text;

        set

        {

            Console.WriteLine("Updating text: " + value);

            text = value;

        }

    }


    public EditorMemento Save()

    {

        Console.WriteLine("Saving state...");

        return new EditorMemento(text);

    }


    public void Restore(EditorMemento memento)

    {

        Console.WriteLine("Restoring state...");

        text = memento.Text;

    }

}


// Memento

class EditorMemento

{

    public string Text { get; }


    public EditorMemento(string text)

    {

        Text = text;

    }

}


// Caretaker

class HistoryManager

{

    private readonly Stack<EditorMemento> history = new Stack<EditorMemento>();

    private readonly Stack<EditorMemento> redoStack = new Stack<EditorMemento>();


    public void SaveState(EditorMemento memento)

    {

        history.Push(memento);

        // Clear redo stack when a new state is saved

        redoStack.Clear();

    }


    public EditorMemento Undo()

    {

        if (history.Count > 1)

        {

            Console.WriteLine("Undoing...");

            var currentState = history.Pop();

            redoStack.Push(currentState);

            return history.Peek();

        }

        else

        {

            Console.WriteLine("Nothing to undo.");

            return history.Peek();

        }

    }


    public EditorMemento Redo()

    {

        if (redoStack.Count > 0)

        {

            Console.WriteLine("Redoing...");

            var nextState = redoStack.Pop();

            history.Push(nextState);

            return nextState;

        }

        else

        {

            Console.WriteLine("Nothing to redo.");

            return history.Peek();

        }

    }

}


// Example Usage

class Program

{

    static void Main()

    {

        TextEditor editor = new TextEditor();

        HistoryManager historyManager = new HistoryManager();


        // User makes changes

        editor.Text = "First line";

        historyManager.SaveState(editor.Save());


        editor.Text = "Second line";

        historyManager.SaveState(editor.Save());


        // Undo to previous state

        EditorMemento previousState = historyManager.Undo();

        editor.Restore(previousState);


        // Redo to the undone state

        EditorMemento nextState = historyManager.Redo();

        editor.Restore(nextState);


        Console.WriteLine("Current text: " + editor.Text);

    }

}


Now, the `HistoryManager` class has a `redoStack` to keep track of the undone states. The `Redo` method allows you to redo an action by popping a state from the redo stack and pushing it back onto the history stack. The `SaveState` method now clears the redo stack whenever a new state is saved, ensuring that redoing is only possible after a new change has been made.




Comments