Memento is a behavioural design pattern that without violating encapsulation, allows object to capture and save its internal state so it can later be restored to this state (undo).

Applicability

  • When you need to implement undo and redo functionality in your application.
  • When you want to provide a way for user to save their progress in an application or game.
  • You want to revert to an object’s original state if unexpected event happens. (especially in transaction systems to revert the transaction to its original state if transaction fails)

Approach

  1. Create Originator class that holds the state you want to capture and restore.
  2. Define the Memento class that stores a snapshot of the Originator’s state.
  3. Create caretaker class for storing and managing Memento objects. It can provide methods to save Mementos and retrieve them when needed.

Components

  • Originator
    • The Originator is the object whose internal state needs to be saved and restored
    • It creates a memento containing a snapshot of its current internal state
    • It uses a memento object to restore its state
  • Memento
    • The memento acts as a snapshot of the Originator’s state
    • It stores the internal state of the Originator object. It may store as much or as little of Originator’s internal state as necessary.
    • It has methods to get and set the state or relevant parts of the state, but it does not directly expose the state to other objects.
    • It can either implemented as an inner class of the Originator or as an external class.
  • Caretaker
    • Responsible for capturing and restoring Originator state.
    • Holds a collection of Mementos, which can be used to save and retrieve history states of the Originator.
    • The caretaker does not modify (Memento is immutable) the Memento objects but acts as a repository for them.

Example

Identify memento pattern components

Originator: TextArea Memento: Memento Caretaker: TextEditor

Originator

We want to store the content of the TextArea, it can create Memento objects to save the current content and restore it if needed.

Memento

The memento here is in a form of an inner class of the Originator. Its methods have private access modifier which enforces the encapsulation that no other class than TextArea can have direct access to its snapshot, if the client wants to retrieve the snapshot it has to access it via the TextArea’s public methods (save(), restore()).

class TextArea {
    private String content;
 
    public setContent(String content) {
        this.content = content;
    }
 
    public String getContent() {
        return content;
    }
 
    // create a Memento object to save the current state (snapshot)
    public Memento save() {
        return new Memento(contentToSave);
    }
 
    // restore the state from a Memento object
    public void restore(Memento memento) {
        this.content = memento.getSavedContent();
    }
 
    // inner Memento class - represents the snapshot of the TextArea
    public static class Memento {
	    // the Memento data should be immutable
        private final String savedContent;
 
		// private Memento methods to enforce encapsulation
        private Memento(String contentToSave) {
            savedContent = contentToSave;
        }
 
        private String getSavedContent() {
            return savedContent;
        }
    }
}

Caretaker

The caretaker class responsible for storing and managing Memento objects.

class TextEditor {
	// stores a list of memento objects
    private final Deque<TextEditor.Memento> historyState;
    private TextArea textArea;
 
	public TextEditorHisotry() {
		historyState = new LikedList<>();
		textArea = new TextArea();
	}
 
    public void write(String content) {
	    textArea.setContent(content);
	    // save the current state and store it to history
        historyState.add(textEditor.save());
    }
 
	public void undo() {
		// undo with the most recent history
		textArea.restore(historyState.pop());
	}
 
	// roll back to a specific history version
    public void revert(int index) {
        textArea.restore(historyState.remove(index));
    }
}

Client

The client creates instances of Originator and Caretaker class, it saves and restores the state of the TextArea using Memento objects.

public class MementoPatternExample {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
		editor.write("Some text");
		editor.write("Some more text");
		editor.write("Even more text");
 
		editor.undo();
}

Back to super node: Behavioural Patterns

Design_PatternBehavioural_Design_Patterns SOFT2201Memento_pattern