Skip to main content
Create your own
Lesson illustration

Implementing the Memento Pattern

Hello! Welcome to your next lesson in our series on behavioral design patterns.

In our previous lesson, we explored the Visitor pattern. We learned how it allows us to add new operations to a stable hierarchy of classes externally, without modifying the classes themselves. This is perfect for when you have a fixed set of data structures but an evolving set of operations.

Today, we're turning our focus inward. Instead of adding external operations, we'll look at how an object can manage its own internal state. The learning outcome for this lesson is to apply the Memento pattern to capture and restore an object's internal state. This pattern is the cornerstone of implementing features like undo/redo functionality, which is a classic low-level design interview problem.

The Problem: How to Implement "Undo" Without Breaking the Rules

Imagine you're designing a text editor. The Editor object has an internal state consisting of its content, fontName, fontSize, and so on.

public class Editor {
    private String content;
    private String fontName;
    private int fontSize;
    // ... getters, setters, and other methods
}

Now, you need to implement an "undo" feature. To do this, you must save a snapshot of the editor's state before each change. A history manager of some kind could then restore a previous snapshot when the user hits "undo".

A naive approach might be for the history manager to directly access the editor's private fields, copy their values, and store them. But this immediately creates a problem: it completely breaks encapsulation. The history manager becomes tightly coupled to the editor's internal structure. If you later decide to add a cursorPosition field to the Editor, you would also have to remember to update the history manager. This makes the system fragile and hard to maintain.

So the core question is: How can we save and restore an object's state from the outside, while letting the object itself maintain control over its private data?

The Solution: The Memento Pattern

The Memento pattern solves this by delegating the responsibility of state management. Instead of an external object trying to pull state from the Editor, the Editor itself packages its own state into a special object called a Memento.

The process works like this:

  1. An external object, the Caretaker (our history manager), asks the Originator (the Editor) to save its state.
  2. The Originator creates a Memento object, fills it with its current state, and hands it back to the Caretaker.
  3. The Caretaker holds onto this Memento. Crucially, it cannot and does not look inside it. To the Caretaker, the Memento is an opaque token.
  4. Later, to perform an undo, the Caretaker gives the Memento back to the Originator.
  5. The Originator, because it created the Memento, knows how to read the state from it and restore itself.

This approach elegantly preserves encapsulation. The Originator has full control over what state is saved and how it's restored, and its internal details are never exposed to other components.

To see this thought process of discovering the pattern from first principles, let's watch a segment from a video by Mosh Hamedani.

Design Patterns in Plain English | Mosh Hamedani

This video walks through the problem of implementing an undo mechanism and guides you through the limitations of simpler solutions to arrive at the Memento pattern's structure.

Watch the section from 40:29 to 48:19. Focus on understanding why simple solutions (like storing previous content in a list within the editor) are not ideal and how separating responsibilities leads to a more robust design with three distinct components.

The Three Roles in the Memento Pattern

As you saw in the video, the Memento pattern involves three key participants. Let's formally define them using their standard names from the "Gang of Four" book.

  • Originator: The object whose state needs to be saved (e.g., our Editor). It creates mementos and can use them to restore its own state.
  • Memento: A value object that stores the state of the Originator. It should be immutable to prevent the Caretaker or other objects from accidentally modifying the stored state.
  • Caretaker: The object that manages the history. It requests mementos, holds them (often in a stack for LIFO undo/redo logic), and passes them back to the Originator for restoration. It never operates on or examines the contents of the Memento.

This class diagram clearly illustrates the relationships between these components.

Class Diagram of Memento Design Pattern
This diagram shows the structure of the Memento pattern. The `Document` (Originator) creates and consumes `DocumentMemento` (Memento) objects. The `History` (Caretaker) stores a list of these mementos but does not interact with their internal state, thus preserving the Originator's encapsulation.

And this sequence diagram shows how they interact to save and restore state.

UML Sequence Diagram for Memento Design Pattern
This sequence diagram shows the two primary workflows. For saving, the Caretaker asks the Originator to create a Memento. For restoring, the Caretaker passes a stored Memento back to the Originator.

Implementation in Java

Now, let's put this into practice by implementing the text editor example. We'll build the three classes that form the pattern.

The following article provides a clear, step-by-step Java implementation that mirrors the concepts we've discussed.

Memento Design Pattern in Java

The article 'Memento Design Pattern in Java' on Baeldung provides a great textual walkthrough of building the pattern. We will use it as our guide for the implementation.

Read Section 4, 'Example of the Memento Pattern,' including all its subsections (4.1 through 4.5). Follow the code to see how the TextWindow (Originator), TextWindowState (Memento), and TextEditor (Caretaker) are built and used together. Notice how the Memento (TextWindowState) is made immutable by using a String and only providing a getter.

To see this implementation come alive, we'll now watch the second part of Mosh Hamedani's video, where he codes the exact same structure.

Design Patterns in Plain English | Mosh Hamedani

This video provides a live coding session of the Memento pattern, implementing the Editor (Originator), EditorState (Memento), and History (Caretaker) classes.

Watch from 48:19 to 54:25. As you follow along, note these key points: The Memento (EditorState): It's a simple class with a final field and a constructor to make it immutable. The Originator (Editor): It has two crucial methods: createState() to produce a memento and restore(EditorState state) to consume one. The Caretaker (History): It uses a List to function as a stack, with push() and pop() methods to manage the history of EditorState objects. Client Code: See how the main method orchestrates the interaction between these three components to achieve the undo functionality.

Test your understanding!

You are building a drawing application. You have a Shape class (the Originator) that has three properties: x (int), y (int), and color (String).

How would you design the Memento and Originator classes to support an undo feature for changes to a shape's properties? Write the basic structure for the Shape and ShapeMemento classes.

Show answer

Here is a possible implementation:

1. The Memento (ShapeMemento)
This class stores the state. It's made immutable with final fields and no setters.

// Memento
public class ShapeMemento {
    private final int x;
    private final int y;
    private final String color;

    public ShapeMemento(int x, int y, String color) {
        this.x = x;
        this.y = y;
        this.color = color;
    }

    // Getters are needed for the Originator to restore the state
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public String getColor() {
        return color;
    }
}

2. The Originator (Shape)
This class creates and consumes the memento.

// Originator
public class Shape {
    private int x;
    private int y;
    private String color;

    // Setters to change the state
    public void setX(int x) { this.x = x; }
    public void setY(int y) { this.y = y; }
    public void setColor(String color) { this.color = color; }

    // Creates the Memento
    public ShapeMemento save() {
        return new ShapeMemento(this.x, this.y, this.color);
    }

    // Restores from a Memento
    public void restore(ShapeMemento memento) {
        this.x = memento.getX();
        this.y = memento.getY();
        this.color = memento.getColor();
    }
    
    @Override
    public String toString() {
        return "Shape{" + "x=" + x + ", y=" + y + ", color='" + color + '\'' + '}';
    }
}

The Caretaker would then hold a Stack<ShapeMemento> to manage the undo history.

Important Consideration: State Size and Performance

The Memento pattern is powerful, but it has a significant trade-off: memory consumption. If the Originator's state is large (e.g., a high-resolution image, a large data file), creating a full snapshot for every change can consume a lot of memory and be slow.

In such cases, you might consider more advanced variations, such as:

  • Saving only the changes (deltas) between states.
  • Implementing incremental snapshots.

However, for most common use cases in interviews and application design, the classic implementation of saving the full state is sufficient and demonstrates your understanding of the pattern.

Conclusion

In this lesson, we've delved into the Memento pattern, a fundamental tool for state management.

Key Takeaways:

  • Purpose: To capture and restore an object's internal state without violating encapsulation. It's the standard solution for undo/redo functionality.
  • Structure: It consists of three roles: the Originator (the object with the state), the Memento (the immutable state snapshot), and the Caretaker (the history manager).
  • Core Benefit: Decouples the object from the mechanism that saves its history, preserving encapsulation and promoting a clean, maintainable design.
  • Trade-off: Can be memory-intensive if the object's state is large.

In our next lesson, we will broaden our perspective to discuss the Model-View-Controller (MVC) architectural pattern. The Memento pattern gives us a way to manage the state of a single "Model" object. MVC provides a high-level structure for organizing the entire application, separating the data and business logic (the Model) from its visual representation (the View) and user input handling (the Controller). Understanding how to manage a model's state is a perfect stepping stone to understanding this larger architecture.

Can't find a good explanation? Sign up and we'll make it for you

Sign up