← All patterns
Behavioral

Memento

Capture an object’s state in a sealed snapshot so it can be restored later without exposing its internals.

What Is It?

The Memento pattern has three roles. The originator is the object whose state matters (a Player). The memento is an immutable snapshot of that state. The caretaker stores mementos and hands one back when asked, but never looks inside.

The key idea is encapsulation: only the originator knows how to build a memento from its fields and how to apply one back. A save system, checkpoint manager or rewind feature can keep dozens of snapshots without depending on what a player actually contains.

In a Unity game this looks like player.Save() returning a PlayerMemento record with position, health and level, a SaveHistory caretaker that keeps a list of them, and player.Restore(memento) snapping everything back when the player dies or loads a checkpoint.

When Is It Used?

Use it for checkpoints, quick-save/quick-load, undo in editors, or a short “rewind time” mechanic where you need to return an object to an earlier state.

It is especially useful when the state is private: the originator stays in charge of what is captured, so you do not have to add public setters just so a save system can poke at it.

Be careful with large or frequently changing state. Snapshotting a whole level every frame is expensive; store deltas, sample less often or limit the history length instead.

Interactive Demo

Click the controls and watch the objects collaborate. The console mirrors what the C# code below would log.

Code

Assets / Scripts / Behavioral/ Memento ›CheckpointTester.cs
using UnityEngine;

namespace Patterns.Behavioral.Memento
{
    /// <summary>
    /// Client: saves and loads checkpoints. It shuttles mementos
    /// between the player and the history without inspecting them.
    /// </summary>
    public class CheckpointTester : MonoBehaviour
    {
        [SerializeField] private Player player;

        private readonly SaveHistory history = new(capacity: 5);

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.F5))
            {
                PlayerMemento snapshot = player.Save();
                history.Push(snapshot);
                Debug.Log($"Saved {snapshot}");
            }

            if (Input.GetKeyDown(KeyCode.F9) && history.Latest != null)
            {
                player.Restore(history.Latest);
                Debug.Log($"Restored {history.Latest}");
            }

            // Mess with the state so there is something to restore.
            if (Input.GetKeyDown(KeyCode.D)) player.TakeDamage(25);
            if (Input.GetKeyDown(KeyCode.L)) player.LevelUp();
            if (Input.GetKeyDown(KeyCode.M)) player.Move(Random.insideUnitSphere * 3f);
        }
    }
}
4 files · namespace Patterns.Behavioral.MementoC# · UTF-8 · LF

Advantages & Disadvantages

+ Advantages

  • Preserves encapsulation — the caretaker treats snapshots as opaque tokens.
  • Immutable snapshots are safe to share and easy to reason about.
  • Simplifies the originator: no undo bookkeeping, just Save() and Restore().

− Disadvantages

  • Snapshots cost memory; long histories of large objects add up quickly.
  • References to other objects (targets, inventory items) are tricky to snapshot and restore correctly.
  • The caretaker cannot tell what changed between snapshots without help from the originator.

Tips

  1. 01Use a C# record or a readonly struct for the memento so nobody can mutate a saved state by accident.
  2. 02Cap the history with a ring buffer for rewind features; drop the oldest snapshot when it is full.
  3. 03For save files, serialize the memento with JsonUtility — it is already a plain data object.
  4. 04Store IDs instead of object references inside a memento, and resolve them on restore.
  5. 05Combine with Command: a command can take a memento before executing and restore it in Undo() when the action is hard to reverse by hand.