Unraveling the Mysteries of the Memento Design Pattern

In the vast landscape of software design patterns, the Memento design pattern stands out as a guardian of the state. Named after the Latin word for “remember,” Memento provides a systematic way to capture and restore an object’s internal state. This design pattern falls under the behavioural category, emphasizing the encapsulation of an object’s internal state, enabling it to be restored to a previous state without revealing its implementation details.

What?

The memento design pattern is a behaviour design pattern that allows you to capture and restore the internal state of an object without violating encapsulation.

Why?

The Memento design pattern addresses specific challenges in software development related to managing and manipulating the state of objects. Here are some key reasons why the Memento pattern, is valuable:

  1. Undo/Redo Functionality: One of the primary use cases for the Memento pattern is to implement undo and redo functionality. By capturing the state of an object at different points in time, you can create a stack of these states. This allows users to undo their actions by restoring the object to a previous state and redo them by moving forward in the stack.
  2. Maintaining State History: The Memento pattern allows you to keep a history of an object’s state changes. This can be valuable for auditing, logging, or any situation where you need to track the evolution of an object’s state over time.
  3. Isolation of State Management: The Memento pattern helps in separating the concerns related to an object’s state and the object itself. The object whose state needs to be managed doesn’t need to expose its internal details directly. Instead, it can provide a memento object that encapsulates its state.
  4. Simplified Interface: Using the Memento pattern can lead to a simpler interface for the originator (the object whose state is being managed). It doesn’t have to expose all its internal details to external clients; instead, it can provide methods for saving and restoring its state using memento objects.
  5. Flexibility in Restoring State: The Memento pattern allows for flexibility in restoring the state of an object. Different versions of an object’s state can be stored, and the client can choose which version to restore based on specific criteria or requirements.

Implementation

The memento design pattern has three components

  • Originator Class
  • Memento Class
  • Caretaker Class
memento design pattern

Originator:
The Originator is the object whose state needs to be captured, stored, and restored. It is responsible for creating and restoring mementos.

Memento:
The Memento is a simple object that serves as a snapshot of the Originator’s state. It does not expose its internal details to the outside world; instead, it provides a way to retrieve the state it encapsulates.

Caretaker:
The Caretaker is responsible for keeping track of the history of Memento objects. It doesn’t have direct knowledge of the Originator’s internal state but holds a collection of mementos.

Code

Originator: Actual functionality

Memento: Originator’s state

Caretaker: Hold the memento

# Memento
class Memento:
    def __init__(self, state):
        self._state = state

    def get_state(self):
        return self._state

# Originator    
class TextEditor:
    def __init__(self):
        self._text = ""

    def write(self, text):
        self._text += text

    def get_text(self):
        return self._text

    def create_memento(self):
        return Memento(self._text)

    def restore(self, memento):
        self._text = memento.get_state()

# Caretaker
class History:
    def __init__(self):
        self._history = []

    def save_memento(self, memento):
        self._history.append(memento)

    def pop(self):
        if self._history:
            return self._history.pop()


# Usage
editor  = TextEditor()
history = History()

editor.write("Hello, ")
history.save_memento(editor.create_memento())

editor.write("world! ")
history.save_memento(editor.create_memento())

editor.write(" BackendMesh ")
history.save_memento(editor.create_memento())


print("Current Text:", editor.get_text()) # Current Text: Hello, world!  BackendMesh 

editor.restore(history.pop())
print("Undo:", editor.get_text()) # Undo: Hello, world!  BackendMesh 

editor.restore(history.pop())
print("Undo:", editor.get_text()) # Undo: Hello, world! 

editor.restore(history.pop())
print("Undo:", editor.get_text()) # Undo: Hello,

Output

Current Text: Hello, world!  BackendMesh 
Undo: Hello, world!  BackendMesh 
Undo: Hello, world! 
Undo: Hello,

Use Case of the Memento Design Pattern

The Memento pattern finds applications in various scenarios, such as:

Text Editors: As demonstrated above, Memento can be used to implement undo and redo functionality in text editors.

Database Rollback: In database management systems, the Memento pattern can be employed to implement rollback mechanisms.

Game State Management: In video game development, Memento can be used to save and restore the state of a game, allowing players to return to a previous point.

Conclusion

The Memento design pattern elegantly addresses the challenge of capturing and restoring an object’s state without exposing its internal details. By encapsulating the state in a separate Memento object, the pattern promotes encapsulation and separation of concerns. Whether you’re building text editors, games, or database systems, the Memento pattern provides a reliable mechanism to “remember” and navigate the history of an object’s state. As you continue your journey in software design, consider adding the Memento pattern to your toolkit for crafting robust and flexible solutions.

Resources

For further exploration, make sure to check out these helpful resources:

Leave a Comment