Memento Pattern

Last Updated on September 24, 2023 by KnownSense

The Memento pattern also known as Token is a behavioral design concept that enables the preservation and retrieval of an object’s prior state discreetly, without exposing the details of its internal structure and implementation.

Imagine creating a text editor app with an undo feature. To save states for undo, the app records object states before operations. However, this approach requires exposing private data, making it fragile and hard to maintain, especially when class structures change.

The Memento pattern tackles this by delegating state snapshot creation to the object itself, maintaining encapsulation. Instead of external objects copying state, the originator object creates snapshots (mementos) with full access to its state. Mementos keep the state private, accessible only through a controlled interface, preserving encapsulation and easing future changes in class structure.

Benefits

  1. State Preservation: It allows you to capture and store the internal state of an object without exposing its details, providing a means to save and restore object states.
  2. Undo and Redo: The pattern facilitates the implementation of undo and redo functionality in applications, enhancing user experience and productivity.
  3. Isolation of Concerns: It separates the responsibility of managing object states from the object itself, improving code organization and adherence to the Single Responsibility Principle.
  4. Maintainability: By encapsulating the state-saving logic within the Memento and Originator objects, it simplifies the codebase and makes it easier to maintain and extend.
  5. Versioning and History: Memento objects can be used to create versioning or history features in applications, allowing users to track changes and revert to previous states.
  6. Support for Caretakers: Caretaker objects can manage multiple Mementos, allowing for more complex undo/redo scenarios and state management.
  7. Flexibility: It provides flexibility for the Originator to determine which aspects of its state to capture in a Memento, supporting selective state management.
  8. Data Recovery: Memento objects can be used for data recovery or persistence, helping to save and retrieve application state across sessions.
  9. Collaboration: In collaborative software, it aids in capturing and restoring shared document states, enabling users to work together effectively.
  10. Enhanced Testing: Memento objects can be used for testing by capturing and restoring known states, facilitating unit testing and debugging.

UML of Memento Pattern

Implementation

Below is the simplified example that demonstrates the Memento Pattern for implementing undo and redo functionality in a text editor.

Step1: Create a class that represents the state of the text editor at a specific point in time.

class EditorMemento {
    private final String content;

    public EditorMemento(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}

Step2: Create a class TextEditor that creates and restores states using Mementos.

class TextEditor {
    private String content;
    private final List<EditorMemento> history = new ArrayList<>();
    private int currentState = -1;

    public void write(String text) {
        // Save the current state and set the new content.
        history.add(new EditorMemento(content));
        content = text;
        currentState++;
    }

    public String getContent() {
        return content;
    }

    public EditorMemento save() {
        return new EditorMemento(content);
    }

    public void restore(EditorMemento memento) {
        content = memento.getContent();
        history.add(memento);
        currentState = history.size() - 1;
    }
}

Step3: Create a Caretaker class that manages a collection of Mementos for undo and redo operations.

class Caretaker {
    private final List<EditorMemento> mementos = new ArrayList<>();
    private int currentIndex = -1;

    public void addMemento(EditorMemento memento) {
         // Remove all future mementos when a new one is added
        while (currentIndex < mementos.size() - 1) {
            mementos.remove(mementos.size() - 1);
        }
        mementos.add(memento);
        currentIndex++;
    }

    public EditorMemento undo() {
        if (currentIndex > 0) {
            currentIndex--;
            return mementos.get(currentIndex);
        }
        return null;  // Cannot undo further
    }

    public EditorMemento redo() {
        if (currentIndex < mementos.size() - 1) {
            currentIndex++;
            return mementos.get(currentIndex);
        }
        return null;  // Cannot redo further
    }
}

Step4: In main class, use the text editor and caretaker and perform redo and undo.

public class MementoPatternExample {
    public static void main(String[] args) {
         // Create a text editor and caretaker
        TextEditor editor = new TextEditor();
        Caretaker caretaker = new Caretaker();

         // Use the text editor and caretaker
        editor.write("Hello, World!");
        caretaker.addMemento(editor.save());
        System.out.println("Current Content: " + editor.getContent());

        editor.write("Adding some text.");
        caretaker.addMemento(editor.save());
        System.out.println("Current Content: " + editor.getContent());

         // Perform Undo
        EditorMemento undoMemento = caretaker.undo();
        if (undoMemento != null) {
            editor.restore(undoMemento);
            System.out.println("Undo: " + editor.getContent());
        } else {
            System.out.println("Cannot undo further.");
        }

         // Perform Redo
        EditorMemento redoMemento = caretaker.redo();
        if (redoMemento != null) {
            editor.restore(redoMemento);
            System.out.println("Redo: " + editor.getContent());
        } else {
            System.out.println("Cannot redo further.");
        }
    }
}

OUTPUT:
Current Content: Hello, World!
Current Content: Adding some text.
Undo: Hello, World!
Redo: Adding some text.

Conclusion

The Memento Pattern is a behavioral design pattern that allows objects to capture and externalize their internal state, enabling them to be restored to a previous state. It promotes encapsulation by separating the responsibility of state management from the object, enhancing the flexibility of undo and redo operations in an application.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top