Java 3 min read

The Memento Design Pattern: Time Travel for Objects

Master the Memento Pattern in Java. Learn how to capture and restore an object's internal state for undo/redo functionality.

MR

Moshiour Rahman

Advertisement

The Problem: Undo Without Violating Encapsulation

Imagine you are building a Text Editor with Undo/Redo.

The naive approach:

class TextEditor {
    public String text;
    public int cursorPosition;
}
// Client code directly accesses .text to save history

This violates encapsulation. Your internal state (text, cursorPosition) is public.

You could use getters, but then anyone can read the state, which might include sensitive data.

The Solution: The Memento Pattern

The Memento Pattern captures and externalizes an object’s internal state so that the object can be restored to this state later, without violating encapsulation.

Real-Life Analogy: Video Game Save Points 🎮

  • Memento: A saved game file.
  • Originator: The game itself (hero position, inventory, health).
  • Caretaker: The save system (manages multiple save slots).

When you load a save, the game restores its state from the file without exposing all internal variables to you.

Visualizing the Pattern

Memento Pattern

Implementation

1. The Memento (The Snapshot)

public class TextMemento {
    private final String text;
    private final int cursorPosition;

    // Constructor is package-private (only Originator can create it)
    TextMemento(String text, int cursorPosition) {
        this.text = text;
        this.cursorPosition = cursorPosition;
    }

    // Only Originator can read the state
    String getText() { return text; }
    int getCursorPosition() { return cursorPosition; }
}

2. The Originator (The Object Being Saved)

public class TextEditor {
    private String text = "";
    private int cursorPosition = 0;

    public void write(String newText) {
        text += newText;
        cursorPosition += newText.length();
    }

    public void moveCursor(int position) {
        this.cursorPosition = position;
    }

    // Save current state
    public TextMemento save() {
        return new TextMemento(text, cursorPosition);
    }

    // Restore from memento
    public void restore(TextMemento memento) {
        this.text = memento.getText();
        this.cursorPosition = memento.getCursorPosition();
    }

    public String getText() { return text; }
}

3. The Caretaker (The History Manager)

import java.util.Stack;

public class History {
    private Stack<TextMemento> history = new Stack<>();

    public void save(TextEditor editor) {
        history.push(editor.save());
    }

    public void undo(TextEditor editor) {
        if (!history.isEmpty()) {
            editor.restore(history.pop());
        }
    }
}

Usage

TextEditor editor = new TextEditor();
History history = new History();

editor.write("Hello");
history.save(editor);

editor.write(" World");
history.save(editor);

editor.write("!!!");
System.out.println(editor.getText()); // "Hello World!!!"

history.undo(editor);
System.out.println(editor.getText()); // "Hello World"

history.undo(editor);
System.out.println(editor.getText()); // "Hello"

In The Wild (Real World Examples)

1. java.io.Serializable

While not a pure Memento, serialization saves an object’s state to bytes, which can be restored later.

2. Database Transactions

A transaction is like a memento. If something fails, you ROLLBACK to the previous state.

Cheat Sheet

FeatureDetails
CategoryBehavioral
Problem SolvedUndo/Redo, Snapshots without breaking encapsulation
Key implementationsave() returns Memento, restore(Memento m)
ProsEncapsulation (Internal state stays private)
ConsMemory (Each memento stores full state, can be expensive)

Tips to Remember 🧠

  • “Game Save”: Think of quicksave/quickload in games.
  • Command vs Memento: Command stores actions (Logged Commands for replay). Memento stores state (Snapshots for rollback).

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.