1. Definition

The Memento pattern provides a mechanism to capture an object’s internal state such that it can be restored to this state later. It involves three key roles: the Originator, the Caretaker, and the Memento.

2. Problem Statement

Imagine developing an application like a text editor where users would want to undo an action. If the application does not maintain a history of its previous states, it would be impossible to revert back to a desired state.

3. Solution

The Memento pattern suggests storing snapshots of an object’s state in a memento object. The caretaker keeps track of these mementos but never modifies them. When the user decides to undo a certain action, the originator can restore its state from a memento provided by the caretaker.

4. Real-World Use Cases

1. Undo functionality in text editors or graphic design software.

2. Saving game progress and allowing players to load a previous save state.

5. Implementation Steps

1. Define the memento object that will store the internal state of the originator.

2. Implement the originator class with methods to save its state to a memento and restore its state from a memento.

3. Utilize a caretaker class to keep track of the various states.

6. Implementation in Java

// Memento class
class Memento {
    private String state;

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

    public String getState() {
        return state;
    }
}

// Originator class
class Originator {
    private String state;

    // Save state
    public Memento save() {
        return new Memento(state);
    }

    // Restore state
    public void restore(Memento memento) {
        this.state = memento.getState();
    }

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

    public String getState() {
        return state;
    }
}

// Caretaker class
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 Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

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

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

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

        // Restoring previous state
        originator.restore(caretaker.get(1));
        System.out.println("Restored State: " + originator.getState());
    }
}

Output:

Current State: State #3
Restored State: State #2

Explanation:

The Originator has methods to save its state to a Memento and to restore its state from a Memento. The Caretaker keeps a list of saved states but doesn't interact with the stored states. When a state is restored using the Memento pattern, we retrieve the desired snapshot from the caretaker and use it to set the state of the originator.

7. When to use?

1. When you want to implement a snapshot functionality that captures an object’s state and allows for a rollback.

2. When direct exposure of an object’s internal state might violate its encapsulation.