Design Pattern 22: Memento Pattern - Complete Guide with Undo/Redo Examples

πŸ“ Download the complete Design Pattern series code from our design_pattern repository.


🎯 What is the Memento Pattern?

The Memento Pattern is a behavioral design pattern that allows you to capture and restore an object’s state without exposing its internal structure. It’s widely used for implementing undo/redo, state recovery, and history management in applications.

Key Benefits:

  • βœ… State recovery - Restore previous states easily
  • βœ… Encapsulation - Internal state is hidden from external objects
  • βœ… Undo/redo support - Implement robust history features
  • βœ… Maintainability - Clean separation of concerns
  • βœ… Extensibility - Add new state types easily

πŸš€ Real-World Problem: Text Editor Undo/Redo

Suppose you are building a text editor with the following requirements:

  • Users can input text and undo changes (Ctrl+Z)
  • The system must save history for recovery
  • The client should not know the details of state management

Business Rules:

  • All state changes are managed by a caretaker
  • The originator creates and restores mementos
  • The client interacts only with simple undo/redo operations

πŸ—οΈ Object-Oriented Analysis (OOA)

Identified Forces:

  1. Data loss risk - No way to recover previous states
  2. High coupling - Client must manage state logic
  3. Hard to extend - Adding new state types is difficult

πŸ’‘ Memento Pattern Solution

By introducing the Memento Pattern, we can capture and restore object states without exposing internal details.

Memento Pattern Components:

  • Originator - Creates and restores state
  • Memento - Stores state
  • Caretaker - Manages history and recovery

πŸ› οΈ Implementation: Text Editor Undo/Redo

1. Originator

class TextEditor {
    private var text: String = ""
    fun type(newText: String) { text += newText }
    fun getText(): String = text
    fun save(): Memento = Memento(text)
    fun restore(memento: Memento) { text = memento.getText() }
    data class Memento(private val state: String) { fun getText(): String = state }
}

2. Caretaker

class History {
    private val mementos = mutableListOf<TextEditor.Memento>()
    fun save(memento: TextEditor.Memento) { mementos.add(memento) }
    fun undo(): TextEditor.Memento? = if (mementos.isNotEmpty()) mementos.removeAt(mementos.size - 1) else null
}

3. Client Code

fun main() {
    val textEditor = TextEditor()
    val history = History()
    textEditor.type("Hello")
    history.save(textEditor.save())
    textEditor.type(", World")
    history.save(textEditor.save())
    textEditor.type("! This is Memento Pattern.")
    println("Current Text: ${textEditor.getText()}")
    textEditor.restore(history.undo()!!)
    println("Undo Text: ${textEditor.getText()}")
    textEditor.restore(history.undo()!!)
    println("Undo Text: ${textEditor.getText()}")
}

Expected Output:

Current Text: Hello, World! This is Memento Pattern.
Undo Text: Hello, World!
Undo Text: Hello

πŸ“Š Memento Pattern vs Alternative Approaches

Approach Pros Cons
Memento Pattern βœ… Encapsulated state
βœ… Undo/redo support
❌ Memory usage for large histories
❌ Caretaker complexity
Direct State Management βœ… Simple for small apps ❌ High coupling
❌ No encapsulation
Event Sourcing βœ… Full history
βœ… Auditing
❌ Complex implementation
❌ Storage overhead

🎯 When to Use the Memento Pattern

βœ… Perfect For:

  • Text editors (undo/redo)
  • Game save systems
  • Workflow engines (rollback)
  • Configuration management
  • Stateful UI components

❌ Avoid When:

  • Large, complex states (memory overhead)
  • Simple, stateless systems

πŸ”§ Advanced Memento Pattern Implementations

  • Multi-level undo/redo
  • State compression for memory optimization
  • Versioning and branching
  • Persistent storage of mementos

πŸ“ˆ Real-World Applications

  • Text editors (VSCode, Word)
  • Drawing and design tools (undo/redo)
  • Game save/load systems
  • Database transaction rollback

🚨 Common Pitfalls and Best Practices

  • Avoid storing large objects in mementos
  • Use immutable mementos for safety
  • Document state transitions clearly


βœ… Conclusion

Through the Memento Pattern, we successfully implemented robust undo/redo and state recovery features, making the system more reliable and user-friendly.

Key Advantages:

  • 🎯 State recovery
  • πŸ”§ Encapsulation
  • πŸ“ˆ Undo/redo support
  • πŸ›‘οΈ Maintainability
  • ⚑ Extensibility

Design Principles Followed:

  • Single Responsibility Principle (SRP): State management is separated
  • Open-Closed Principle (OCP): Add new state types easily
  • Don’t Repeat Yourself (DRY): Centralize state logic

Perfect For:

  • Text editors
  • Game save systems
  • Workflow engines

The Memento Pattern provides an elegant solution for state recovery and undo/redo in modern applications!


πŸ’‘ Pro Tip: Use immutable mementos and avoid storing large objects to optimize performance.

πŸ”” Stay Updated: Follow our Design Pattern series for more software architecture insights!




    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • How to Use Multiple GitHub Accounts on One Computer: Complete SSH Setup Guide
  • Excalidraw AI: Create Professional Diagrams with Text Commands - Complete Guide
  • Complete macOS Development Environment Setup Guide for 2024
  • Design Pattern 28: Interpreter Pattern - Complete Guide with Examples
  • Design Pattern 27: Visitor Pattern - Complete Guide with Real-World IoT Examples