Memento Design Pattern in Java

1. Definition

The Memento Design Pattern provides the ability to restore an object to its previous state, which can be useful for "undo" functionality in applications.

2. Problem Statement

How can we implement the undo or rollback operations for objects without violating the encapsulation principle of OOP?

3. Solution

Capture and externalize an object's internal state without violating encapsulation, so that the object can be restored to this state later. This can be achieved by introducing a memento object and a caretaker. The memento holds the internal state of the originator, and the caretaker ensures the state's safekeeping without knowing the details.

4. Real-World Use Cases

1. Undo functionality in a text editor.

2. Snapshot of system configurations.

3. Saving game progress in video games.

5. Implementation Steps

1. Create the Originator class that has a state and methods to set, save, and restore state.

2. Implement the Memento class that will hold the state of the Originator.

3. Implement the Caretaker class that will store the mementos but won't modify or inspect their content.

6. Implementation

// Memento
class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

// Originator
class Originator {
    private String state;

    // Sets the state
    public void setState(String state) {
        this.state = state;
    }

    // Gets the state
    public String getState() {
        return state;
    }

    // Saves the current state and returns a new Memento with the saved state
    public Memento saveStateToMemento() {
        return new Memento(state);
    }

    // Restores the state from a Memento
    public void getStateFromMemento(Memento memento) {
        state = memento.getState();
    }
}

// Caretaker
class Caretaker {
    private List<Memento> mementoList = new ArrayList<>();

    public void add(Memento state) {
        mementoList.add(state);
    }

    public Memento get(int index) {
        return mementoList.get(index);
    }
}

// Client
public class MementoDemo {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("State #1");
        caretaker.add(originator.saveStateToMemento());

        originator.setState("State #2");
        caretaker.add(originator.saveStateToMemento());

        originator.setState("State #3");
        System.out.println("Current State: " + originator.getState());

        // Restore state from the first memento
        originator.getStateFromMemento(caretaker.get(0));
        System.out.println("Restored State: " + originator.getState());
    }
}

Output:

Current State: State #3
Restored State: State #1

Explanation

The Memento pattern allows the Originator to save its internal state outside without exposing its internals. Later, it can use the saved memento to revert to a previous state. In this example, the Caretaker only adds or fetches mementos, ensuring that encapsulation is not violated.

7. When to use?

Use the Memento Pattern when:

1. You want to produce snapshots of an object's state to restore it to a previous state.

2. Direct access to the object's fields/getters/setters would expose details and violate its encapsulation.


Comments