Skip to content
kgleong edited this page Oct 28, 2015 · 3 revisions

Motivation

The Momento design pattern is useful in the following situation:

  • Snapshots of the state of an object are required. This may be to support restoration of an object or undoable operations.
  • The internals of the object should be kept hidden from external classes.

The object being tracked is called the originator.

The snapshots are referred to as momentos.

Code

public class Originator {
    private String mStatus = "initialized";

    public Memento setStatus(String status) {
        mStatus = status;
        System.out.println("Status changed to: " + status);
    }

    public Memento createSnapshot() {
        return new Memento(mStatus);
    }

    public void restoreSnapshot(Memento memento) {
        mStatus = memento.mStatus;
        System.out.println("Originator restored to status: " + mStatus);
    }

    // Used by an external history manager to restore Originator state.
    // It is important to note that Momento data/methods should be private,
    // making them only accessible by Originator instances.
    public static class Memento {
        private String mStatus;

        public Memento(String status) {
            mStatus = status;
        }
    }
}

Originatorinstances are the only objects that an access or manipulate the data contained in Originator.Memento objects.

By keeping Memento objects opaque to external classes, this preserves the level of abstraction of the Originator class. This keeps any unnecessary implementation details in the Originator hidden from clients.

The Memento class stores any data necessary to restore an Originator to a previous state. This data can be incremental when a history of changes is preserved such that any state can be restored by reversing any subsequent changes.

Otherwise, it can store the complete state of the Originator object at the time of the snapshot.

// Client usage
Originator originator = new Originator();

// History list
Stack<Originator.Memento> historyList = new Stack<>();

// Change status and keep history.
historyList.push(originator.createSnapshot());
originator.setStatus("pending");
historyList.push(originator.createSnapshot());
originator.setStatus("complete");

// Reverse status changes.
while(!stack.empty()) {
    Origininator.Memento memento = stack.pop();
    originator.restoreSnapshot(memento);
}

// Output:
// Status changed to: pending
// Status changed to: complete
// Originator restored to status: pending
// Originator restored to status: initialized

The Stack<Originator.Memento> in the example above is known as a caretaker, which is responsible for managing Memento instances.

The caretaker, however, should not have any knowledge of the contents or implementation details of any of the Memento instances it oversees.

In order to process a Memento object, it is passed back to the Originator instance that spawned it.

Use Case

The Memento pattern can be used in conjuction with the Command design pattern.

public class ConcreteCommand implements Command {
    private Originator.Momento mMomento;
    private Originator mReceiver;

    public ConcreteCommand(Originator receiver) {
        mReceiver = receiver;
    }

    @Override
    public void execute() {
        // Create a snapshot before changes occur.
        mMomento = mReceiver.createSnapshot();

        mReceiver.execute();
    }

    @Override
    public void undo() {
        mReceiver.restoreSnapshot(mMomento);
    }
}

In the example above, rolling back a change is supported, but the Momento keeps the internals of the receiver hidden from the ConcreteCommand class.

References

Clone this wiki locally