Skip to content

Memento Pattern

Category: Behavioral Pattern

Overview

Capture and externalize an object's internal state without violating encapsulation, so that the object can be restored to this state later. This pattern is useful for implementing undo/redo functionality, checkpoints, and snapshots while preserving object encapsulation.

Usage Guidelines

Use when:

  • Need to implement undo and redo functionality
  • Want to save object state at specific points in time
  • Need to rollback to previous states
  • Creating save points in games or applications

Avoid when:

  • State is simple and can be easily recreated
  • Storing many mementos consumes too much memory
  • All state is already public
  • Never need to restore previous states

Implementation

from __future__ import annotations
from typing import Any

class Memento:
    """Stores the internal state of the Originator."""

    def __init__(self, state: Any) -> None:
        """Initialize memento with state."""
        self._state = state

    def get_state(self) -> Any:
        """Get the stored state."""
        return self._state

class TextEditor:
    """Originator class that creates and restores mementos."""

    def __init__(self) -> None:
        """Initialize text editor with empty content."""
        self._content: str = ""

    def write(self, text: str) -> None:
        """Add text to the editor."""
        self._content += text

    def get_content(self) -> str:
        """Get current content."""
        return self._content

    def save(self) -> Memento:
        """Create a memento with current state."""
        return Memento(self._content)

    def restore(self, memento: Memento) -> None:
        """Restore state from memento."""
        self._content = memento.get_state()

class History:
    """Caretaker that manages mementos."""

    def __init__(self) -> None:
        """Initialize empty history."""
        self._mementos: list[Memento] = []

    def save(self, editor: TextEditor) -> None:
        """Save current editor state."""
        self._mementos.append(editor.save())

    def undo(self, editor: TextEditor) -> bool:
        """Undo to previous state."""
        if len(self._mementos) <= 1:
            if self._mementos:
                self._mementos.pop()
                editor.restore(Memento(""))  # Restore to empty
                return True
            return False

        self._mementos.pop()  # Remove most recent state
        editor.restore(self._mementos[-1])  # Restore to previous state
        return True

Usage

# Text editor with undo
editor = TextEditor()
history = History()

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

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

editor.write("!")
print(editor.get_content())  # "Hello World!"

history.undo(editor)
print(editor.get_content())  # "Hello World"

history.undo(editor)
print(editor.get_content())  # "Hello "

Trade-offs

Benefits:

  1. Encapsulation preserved with internal state saved without exposing structure
  2. Simplified originator that doesn't manage its own history
  3. Easy to implement undo and redo operations
  4. Can save multiple snapshots at different points

Drawbacks:

  1. Storing many mementos uses significant memory
  2. Creating mementos can be expensive for large objects
  3. Caretaker must manage memento lifecycle
  4. Large state makes mementos expensive

Real-World Examples

  • Text editors with undo/redo functionality
  • Version control systems like Git with commits and checkpoints
  • Database transactions with rollback and commit
  • Games with save points and quick saves
  • Command
  • Iterator
  • Prototype
  • Caretaker

API Reference

design_patterns.behavioral.memento

Memento Pattern Module

The Memento pattern captures and externalizes an object's internal state without violating encapsulation, so that the object can be restored to this state later. It's useful for implementing undo/redo functionality, checkpoints, and snapshots.

Example

Text editor with undo functionality:

editor = TextEditor()
history = History()

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

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

editor.write("!!!")

history.undo(editor)  # Back to "Hello World!"
history.undo(editor)  # Back to "Hello "

CheckpointManager

Manages game checkpoints.

Source code in src/design_patterns/behavioral/memento.py
class CheckpointManager:
    """Manages game checkpoints."""

    def __init__(self) -> None:
        """Initialize checkpoint manager."""
        self._checkpoints: list[GameMemento] = []

    def save_checkpoint(self, game: GameState) -> None:
        """Save a checkpoint.

        Args:
            game: Game state to save.
        """
        self._checkpoints.append(game.save_checkpoint())

    def load_checkpoint(self, game: GameState, index: int = -1) -> bool:
        """Load a checkpoint.

        Args:
            game: Game state to restore.
            index: Checkpoint index (-1 for most recent).

        Returns:
            True if checkpoint was loaded successfully.
        """
        if not self._checkpoints:
            return False

        if -len(self._checkpoints) <= index < len(self._checkpoints):
            game.load_checkpoint(self._checkpoints[index])
            return True

        return False

    def get_checkpoint_count(self) -> int:
        """Get number of saved checkpoints.

        Returns:
            Number of checkpoints.
        """
        return len(self._checkpoints)

    def clear_checkpoints(self) -> None:
        """Clear all checkpoints."""
        self._checkpoints.clear()

__init__()

Initialize checkpoint manager.

Source code in src/design_patterns/behavioral/memento.py
def __init__(self) -> None:
    """Initialize checkpoint manager."""
    self._checkpoints: list[GameMemento] = []

clear_checkpoints()

Clear all checkpoints.

Source code in src/design_patterns/behavioral/memento.py
def clear_checkpoints(self) -> None:
    """Clear all checkpoints."""
    self._checkpoints.clear()

get_checkpoint_count()

Get number of saved checkpoints.

Returns:

Type Description
int

Number of checkpoints.

Source code in src/design_patterns/behavioral/memento.py
def get_checkpoint_count(self) -> int:
    """Get number of saved checkpoints.

    Returns:
        Number of checkpoints.
    """
    return len(self._checkpoints)

load_checkpoint(game, index=-1)

Load a checkpoint.

Parameters:

Name Type Description Default
game GameState

Game state to restore.

required
index int

Checkpoint index (-1 for most recent).

-1

Returns:

Type Description
bool

True if checkpoint was loaded successfully.

Source code in src/design_patterns/behavioral/memento.py
def load_checkpoint(self, game: GameState, index: int = -1) -> bool:
    """Load a checkpoint.

    Args:
        game: Game state to restore.
        index: Checkpoint index (-1 for most recent).

    Returns:
        True if checkpoint was loaded successfully.
    """
    if not self._checkpoints:
        return False

    if -len(self._checkpoints) <= index < len(self._checkpoints):
        game.load_checkpoint(self._checkpoints[index])
        return True

    return False

save_checkpoint(game)

Save a checkpoint.

Parameters:

Name Type Description Default
game GameState

Game state to save.

required
Source code in src/design_patterns/behavioral/memento.py
def save_checkpoint(self, game: GameState) -> None:
    """Save a checkpoint.

    Args:
        game: Game state to save.
    """
    self._checkpoints.append(game.save_checkpoint())

ConfigMemento

Memento for configuration.

Source code in src/design_patterns/behavioral/memento.py
class ConfigMemento:
    """Memento for configuration."""

    def __init__(self, settings: dict[str, Any]) -> None:
        """Initialize config memento.

        Args:
            settings: Settings to store.
        """
        self._settings = settings

    def get_state(self) -> dict[str, Any]:
        """Get stored settings.

        Returns:
            Copy of stored settings.
        """
        return self._settings.copy()

__init__(settings)

Initialize config memento.

Parameters:

Name Type Description Default
settings dict[str, Any]

Settings to store.

required
Source code in src/design_patterns/behavioral/memento.py
def __init__(self, settings: dict[str, Any]) -> None:
    """Initialize config memento.

    Args:
        settings: Settings to store.
    """
    self._settings = settings

get_state()

Get stored settings.

Returns:

Type Description
dict[str, Any]

Copy of stored settings.

Source code in src/design_patterns/behavioral/memento.py
def get_state(self) -> dict[str, Any]:
    """Get stored settings.

    Returns:
        Copy of stored settings.
    """
    return self._settings.copy()

Configuration

Configuration object with memento support.

Source code in src/design_patterns/behavioral/memento.py
class Configuration:
    """Configuration object with memento support."""

    def __init__(self) -> None:
        """Initialize configuration with defaults."""
        self.settings: dict[str, Any] = {
            "theme": "light",
            "language": "en",
            "auto_save": True,
            "font_size": 12
        }

    def set(self, key: str, value: Any) -> None:
        """Set a configuration value.

        Args:
            key: Setting key.
            value: Setting value.
        """
        self.settings[key] = value

    def get(self, key: str, default: Any = None) -> Any:
        """Get a configuration value.

        Args:
            key: Setting key.
            default: Default value if key not found.

        Returns:
            Setting value or default.
        """
        return self.settings.get(key, default)

    def create_snapshot(self) -> ConfigMemento:
        """Create a snapshot of current configuration.

        Returns:
            Memento with current settings.
        """
        return ConfigMemento(self.settings.copy())

    def restore_snapshot(self, memento: ConfigMemento) -> None:
        """Restore configuration from snapshot.

        Args:
            memento: Snapshot to restore.
        """
        self.settings = memento.get_state()

__init__()

Initialize configuration with defaults.

Source code in src/design_patterns/behavioral/memento.py
def __init__(self) -> None:
    """Initialize configuration with defaults."""
    self.settings: dict[str, Any] = {
        "theme": "light",
        "language": "en",
        "auto_save": True,
        "font_size": 12
    }

create_snapshot()

Create a snapshot of current configuration.

Returns:

Type Description
ConfigMemento

Memento with current settings.

Source code in src/design_patterns/behavioral/memento.py
def create_snapshot(self) -> ConfigMemento:
    """Create a snapshot of current configuration.

    Returns:
        Memento with current settings.
    """
    return ConfigMemento(self.settings.copy())

get(key, default=None)

Get a configuration value.

Parameters:

Name Type Description Default
key str

Setting key.

required
default Any

Default value if key not found.

None

Returns:

Type Description
Any

Setting value or default.

Source code in src/design_patterns/behavioral/memento.py
def get(self, key: str, default: Any = None) -> Any:
    """Get a configuration value.

    Args:
        key: Setting key.
        default: Default value if key not found.

    Returns:
        Setting value or default.
    """
    return self.settings.get(key, default)

restore_snapshot(memento)

Restore configuration from snapshot.

Parameters:

Name Type Description Default
memento ConfigMemento

Snapshot to restore.

required
Source code in src/design_patterns/behavioral/memento.py
def restore_snapshot(self, memento: ConfigMemento) -> None:
    """Restore configuration from snapshot.

    Args:
        memento: Snapshot to restore.
    """
    self.settings = memento.get_state()

set(key, value)

Set a configuration value.

Parameters:

Name Type Description Default
key str

Setting key.

required
value Any

Setting value.

required
Source code in src/design_patterns/behavioral/memento.py
def set(self, key: str, value: Any) -> None:
    """Set a configuration value.

    Args:
        key: Setting key.
        value: Setting value.
    """
    self.settings[key] = value

GameMemento

Memento for game state.

Source code in src/design_patterns/behavioral/memento.py
class GameMemento:
    """Memento for game state."""

    def __init__(
        self,
        level: int,
        score: int,
        lives: int,
        position: tuple[int, int]
    ) -> None:
        """Initialize game memento.

        Args:
            level: Current level.
            score: Current score.
            lives: Remaining lives.
            position: Player position.
        """
        self._state = {
            "level": level,
            "score": score,
            "lives": lives,
            "position": position
        }

    def get_state(self) -> dict[str, Any]:
        """Get saved game state.

        Returns:
            Dictionary containing game state.
        """
        return self._state.copy()

__init__(level, score, lives, position)

Initialize game memento.

Parameters:

Name Type Description Default
level int

Current level.

required
score int

Current score.

required
lives int

Remaining lives.

required
position tuple[int, int]

Player position.

required
Source code in src/design_patterns/behavioral/memento.py
def __init__(
    self,
    level: int,
    score: int,
    lives: int,
    position: tuple[int, int]
) -> None:
    """Initialize game memento.

    Args:
        level: Current level.
        score: Current score.
        lives: Remaining lives.
        position: Player position.
    """
    self._state = {
        "level": level,
        "score": score,
        "lives": lives,
        "position": position
    }

get_state()

Get saved game state.

Returns:

Type Description
dict[str, Any]

Dictionary containing game state.

Source code in src/design_patterns/behavioral/memento.py
def get_state(self) -> dict[str, Any]:
    """Get saved game state.

    Returns:
        Dictionary containing game state.
    """
    return self._state.copy()

GameState

Represents game state for checkpoint system.

Source code in src/design_patterns/behavioral/memento.py
class GameState:
    """Represents game state for checkpoint system."""

    def __init__(self) -> None:
        """Initialize game state."""
        self.level: int = 1
        self.score: int = 0
        self.lives: int = 3
        self.position: tuple[int, int] = (0, 0)

    def advance_level(self) -> None:
        """Advance to next level."""
        self.level += 1

    def add_score(self, points: int) -> None:
        """Add points to score.

        Args:
            points: Points to add.
        """
        self.score += points

    def lose_life(self) -> None:
        """Lose a life."""
        self.lives = max(0, self.lives - 1)

    def set_position(self, x: int, y: int) -> None:
        """Set player position.

        Args:
            x: X coordinate.
            y: Y coordinate.
        """
        self.position = (x, y)

    def save_checkpoint(self) -> GameMemento:
        """Create a checkpoint.

        Returns:
            Memento with current game state.
        """
        return GameMemento(
            level=self.level,
            score=self.score,
            lives=self.lives,
            position=self.position
        )

    def load_checkpoint(self, memento: GameMemento) -> None:
        """Load from checkpoint.

        Args:
            memento: Checkpoint to load.
        """
        state = memento.get_state()
        self.level = state["level"]
        self.score = state["score"]
        self.lives = state["lives"]
        self.position = state["position"]

__init__()

Initialize game state.

Source code in src/design_patterns/behavioral/memento.py
def __init__(self) -> None:
    """Initialize game state."""
    self.level: int = 1
    self.score: int = 0
    self.lives: int = 3
    self.position: tuple[int, int] = (0, 0)

add_score(points)

Add points to score.

Parameters:

Name Type Description Default
points int

Points to add.

required
Source code in src/design_patterns/behavioral/memento.py
def add_score(self, points: int) -> None:
    """Add points to score.

    Args:
        points: Points to add.
    """
    self.score += points

advance_level()

Advance to next level.

Source code in src/design_patterns/behavioral/memento.py
def advance_level(self) -> None:
    """Advance to next level."""
    self.level += 1

load_checkpoint(memento)

Load from checkpoint.

Parameters:

Name Type Description Default
memento GameMemento

Checkpoint to load.

required
Source code in src/design_patterns/behavioral/memento.py
def load_checkpoint(self, memento: GameMemento) -> None:
    """Load from checkpoint.

    Args:
        memento: Checkpoint to load.
    """
    state = memento.get_state()
    self.level = state["level"]
    self.score = state["score"]
    self.lives = state["lives"]
    self.position = state["position"]

lose_life()

Lose a life.

Source code in src/design_patterns/behavioral/memento.py
def lose_life(self) -> None:
    """Lose a life."""
    self.lives = max(0, self.lives - 1)

save_checkpoint()

Create a checkpoint.

Returns:

Type Description
GameMemento

Memento with current game state.

Source code in src/design_patterns/behavioral/memento.py
def save_checkpoint(self) -> GameMemento:
    """Create a checkpoint.

    Returns:
        Memento with current game state.
    """
    return GameMemento(
        level=self.level,
        score=self.score,
        lives=self.lives,
        position=self.position
    )

set_position(x, y)

Set player position.

Parameters:

Name Type Description Default
x int

X coordinate.

required
y int

Y coordinate.

required
Source code in src/design_patterns/behavioral/memento.py
def set_position(self, x: int, y: int) -> None:
    """Set player position.

    Args:
        x: X coordinate.
        y: Y coordinate.
    """
    self.position = (x, y)

History

Caretaker that manages mementos.

Source code in src/design_patterns/behavioral/memento.py
class History:
    """Caretaker that manages mementos."""

    def __init__(self) -> None:
        """Initialize empty history."""
        self._mementos: list[Memento] = []

    def save(self, editor: TextEditor) -> None:
        """Save current editor state.

        Args:
            editor: Editor to save.
        """
        self._mementos.append(editor.save())

    def undo(self, editor: TextEditor) -> bool:
        """Undo to previous state.

        Args:
            editor: Editor to restore.

        Returns:
            True if undo was successful, False if no history.
        """
        if len(self._mementos) <= 1:
            if self._mementos:
                self._mementos.pop()
                editor.restore(Memento(""))  # Restore to empty
                return True
            return False

        self._mementos.pop()  # Remove most recent state
        editor.restore(self._mementos[-1])  # Restore to previous state

        return True

    def get_history_size(self) -> int:
        """Get number of saved states.

        Returns:
            Number of states in history.
        """
        return len(self._mementos)

__init__()

Initialize empty history.

Source code in src/design_patterns/behavioral/memento.py
def __init__(self) -> None:
    """Initialize empty history."""
    self._mementos: list[Memento] = []

get_history_size()

Get number of saved states.

Returns:

Type Description
int

Number of states in history.

Source code in src/design_patterns/behavioral/memento.py
def get_history_size(self) -> int:
    """Get number of saved states.

    Returns:
        Number of states in history.
    """
    return len(self._mementos)

save(editor)

Save current editor state.

Parameters:

Name Type Description Default
editor TextEditor

Editor to save.

required
Source code in src/design_patterns/behavioral/memento.py
def save(self, editor: TextEditor) -> None:
    """Save current editor state.

    Args:
        editor: Editor to save.
    """
    self._mementos.append(editor.save())

undo(editor)

Undo to previous state.

Parameters:

Name Type Description Default
editor TextEditor

Editor to restore.

required

Returns:

Type Description
bool

True if undo was successful, False if no history.

Source code in src/design_patterns/behavioral/memento.py
def undo(self, editor: TextEditor) -> bool:
    """Undo to previous state.

    Args:
        editor: Editor to restore.

    Returns:
        True if undo was successful, False if no history.
    """
    if len(self._mementos) <= 1:
        if self._mementos:
            self._mementos.pop()
            editor.restore(Memento(""))  # Restore to empty
            return True
        return False

    self._mementos.pop()  # Remove most recent state
    editor.restore(self._mementos[-1])  # Restore to previous state

    return True

Memento

Stores the internal state of the Originator.

Source code in src/design_patterns/behavioral/memento.py
class Memento:
    """Stores the internal state of the Originator."""

    def __init__(self, state: Any) -> None:
        """Initialize memento with state.

        Args:
            state: State to store.
        """
        self._state = state

    def get_state(self) -> Any:
        """Get the stored state.

        Returns:
            The stored state.
        """
        return self._state

__init__(state)

Initialize memento with state.

Parameters:

Name Type Description Default
state Any

State to store.

required
Source code in src/design_patterns/behavioral/memento.py
def __init__(self, state: Any) -> None:
    """Initialize memento with state.

    Args:
        state: State to store.
    """
    self._state = state

get_state()

Get the stored state.

Returns:

Type Description
Any

The stored state.

Source code in src/design_patterns/behavioral/memento.py
def get_state(self) -> Any:
    """Get the stored state.

    Returns:
        The stored state.
    """
    return self._state

TextEditor

Originator class that creates and restores mementos.

Source code in src/design_patterns/behavioral/memento.py
class TextEditor:
    """Originator class that creates and restores mementos."""

    def __init__(self) -> None:
        """Initialize text editor with empty content."""
        self._content: str = ""

    def write(self, text: str) -> None:
        """Add text to the editor.

        Args:
            text: Text to add.
        """
        self._content += text

    def get_content(self) -> str:
        """Get current content.

        Returns:
            Current content.
        """
        return self._content

    def save(self) -> Memento:
        """Create a memento with current state.

        Returns:
            Memento containing current state.
        """
        return Memento(self._content)

    def restore(self, memento: Memento) -> None:
        """Restore state from memento.

        Args:
            memento: Memento to restore from.
        """
        self._content = memento.get_state()

__init__()

Initialize text editor with empty content.

Source code in src/design_patterns/behavioral/memento.py
def __init__(self) -> None:
    """Initialize text editor with empty content."""
    self._content: str = ""

get_content()

Get current content.

Returns:

Type Description
str

Current content.

Source code in src/design_patterns/behavioral/memento.py
def get_content(self) -> str:
    """Get current content.

    Returns:
        Current content.
    """
    return self._content

restore(memento)

Restore state from memento.

Parameters:

Name Type Description Default
memento Memento

Memento to restore from.

required
Source code in src/design_patterns/behavioral/memento.py
def restore(self, memento: Memento) -> None:
    """Restore state from memento.

    Args:
        memento: Memento to restore from.
    """
    self._content = memento.get_state()

save()

Create a memento with current state.

Returns:

Type Description
Memento

Memento containing current state.

Source code in src/design_patterns/behavioral/memento.py
def save(self) -> Memento:
    """Create a memento with current state.

    Returns:
        Memento containing current state.
    """
    return Memento(self._content)

write(text)

Add text to the editor.

Parameters:

Name Type Description Default
text str

Text to add.

required
Source code in src/design_patterns/behavioral/memento.py
def write(self, text: str) -> None:
    """Add text to the editor.

    Args:
        text: Text to add.
    """
    self._content += text