Python Memento Design Pattern

1. Definition

The Memento Design Pattern allows for the ability to restore an object to its previous state, which can be useful for operations like undo.

2. Problem Statement

Sometimes it's necessary to record the internal state of an object without exposing its internal structure and without breaking the principles of encapsulation. For example, in applications that provide undo functionality.

3. Solution

The Memento pattern achieves this by introducing three actor classes: Originator, Caretaker, and Memento. The Originator is the object whose state we want to save. The Caretaker is the one that keeps the list of states (mementos). Memento is the value object where the state of the Originator is stored.

4. Real-World Use Cases

1. Text editor undo mechanism.

2. Game save and load functionality.

3. Snapshot functionality in VMs or databases.

5. Implementation Steps

1. Create a Memento class that only the Originator can read and write.

2. The Originator class creates a memento containing a snapshot of its internal state and can also restore its state from a memento.

3. The Caretaker class keeps track of multiple mementos but never operates on them.

6. Implementation in Python

# Memento
class Memento:
    def __init__(self, state):
        self._state = state
    def get_saved_state(self):
        return self._state
# Originator
class Originator:
    _state = ""
    def set(self, state):
        self._state = state
    def save_to_memento(self):
        return Memento(self._state)
    def restore_from_memento(self, memento):
        self._state = memento.get_saved_state()
# Caretaker
class Caretaker:
    _saved_states = []
    def add_memento(self, memento):
        self._saved_states.append(memento)
    def get_memento(self, index):
        return self._saved_states[index]
# Client code
originator = Originator()
caretaker = Caretaker()
originator.set("State1")
originator.set("State2")
caretaker.add_memento(originator.save_to_memento())
originator.set("State3")
caretaker.add_memento(originator.save_to_memento())
originator.set("State4")
print("Current State:", originator._state)
originator.restore_from_memento(caretaker.get_memento(1))
print("Restored to State:", originator._state)

Output:

Current State: State4
Restored to State: State3

Explanation:

1. The Originator first sets its state to different values and saves these states using Mementos via the Caretaker.

2. The Caretaker holds these states without actually examining or modifying them.

3. The Originator's state is set to "State4", but then we decide to restore it to a previous state ("State3") using a memento retrieved from the Caretaker.

4. This showcases the undo functionality and the principle of encapsulation as the state is never directly accessed or modified by anyone other than the Originator.

7. When to use?

Use the Memento Pattern when:

1. You need to implement a snapshot of an object's state so that you can restore the snapshot later.

2. Direct exposure of an object's private data or details isn't acceptable, but you still want to save its state.

3. You want a structured way to implement the undo mechanism in your applications.


Comments