4.6. Memento
The Memento pattern is a behavioral design pattern that provides the ability to restore an object’s state to a previous state without exposing its internal implementation. This pattern can be useful for implementing undo/redo functionality, taking snapshots of object states, or creating checkpoints in an application.
The Memento pattern is typically used when:
- You want to capture and store the internal state of an object without exposing its implementation.
- You want to provide a way to restore the object to a previous state.
- You want to implement undo/redo functionality or create checkpoints in an application.
To implement the Memento pattern, follow these steps:
- Create a memento class that stores the internal state of the originator object. The memento should be immutable and should not expose its internal data.
- Define a caretaker class or object that is responsible for managing the mementos, including storing and retrieving them.
- In the originator class, implement methods to create a memento (i.e., capture its internal state) and restore its state from a memento.
- In the client code, use the caretaker to store and retrieve mementos, and use the originator to create and restore its state.
Here’s a simple example of the Memento pattern in Java:
// Memento class
class Memento {
private final String state;
public Memento(String state) {
this.state = state;
}
private String getState() {
return state;
}
}
// Originator class
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public Memento saveToMemento() {
return new Memento(state);
}
public void restoreFromMemento(Memento memento) {
state = memento.getState();
}
}
// Caretaker class
class Caretaker {
private final List<Memento> mementos = new ArrayList<>();
public void addMemento(Memento memento) {
mementos.add(memento);
}
public Memento getMemento(int index) {
return mementos.get(index);
}
}
// Client code
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State1");
caretaker.addMemento(originator.saveToMemento());
originator.setState("State2");
caretaker.addMemento(originator.saveToMemento());
originator.restoreFromMemento(caretaker.getMemento(0));
System.out.println(originator.getState()); // Outputs: State1
}
}
In this example, the Memento
class stores the internal state of the Originator
object. The Originator
class provides methods to save its state to a memento and restore its state from a memento. The Caretaker
class manages the mementos, storing and retrieving them as needed.
Advantages of the Memento pattern:
- Encapsulation: The Memento pattern preserves the encapsulation of the originator’s internal state by not exposing its implementation.
- Simplified originator: The pattern keeps the originator’s state management logic simple by delegating the responsibility of state capture and restoration to the memento and caretaker.
Disadvantages of the Memento pattern:
- Increased memory usage: The Memento pattern can lead to increased memory usage if many mementos are stored, especially if the originator’s state is large or complex.
- Complexity: The pattern introduces additional complexity in the form of the memento and caretaker classes, which may make the code more difficult to understand and maintain.
When using the Memento pattern, carefully consider its advantages and disadvantages. Use the pattern when you need to capture and restore an object’s state without exposing its internal implementation, and when you want to provide undo/redo functionality or create checkpoints in an application. Be aware of the potential memory usage and complexity introduced by the pattern, and ensure that it is applied judiciously to maintain a clean and understandable codebase.
Note: For complete list of design patterns click here