Overview
The Memento Design Pattern provides a way to capture and restore the internal state of an object without violating its encapsulation. It is often used to implement undo/redo functionality in applications.
Key Characteristics
- Captures the internal state of an object at a specific moment.
- Allows the object's state to be restored later.
- Ensures encapsulation by preventing external classes from accessing the object's internal details.
Implementation
The following is an example of a Memento implementation in Java:
// Memento
class Memento {
private final String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// Originator
class Originator {
private String state;
public void setState(String state) {
this.state = state;
System.out.println("State set to: " + state);
}
public String getState() {
return state;
}
public Memento saveStateToMemento() {
return new Memento(state);
}
public void restoreStateFromMemento(Memento memento) {
state = memento.getState();
System.out.println("State restored to: " + state);
}
}
// Caretaker
class Caretaker {
private final List mementoList = new ArrayList<>();
public void addMemento(Memento memento) {
mementoList.add(memento);
}
public Memento getMemento(int index) {
return mementoList.get(index);
}
}
// Demo
public class MementoDemo {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State 1");
caretaker.addMemento(originator.saveStateToMemento());
originator.setState("State 2");
caretaker.addMemento(originator.saveStateToMemento());
originator.setState("State 3");
System.out.println("Restoring state...");
originator.restoreStateFromMemento(caretaker.getMemento(0));
originator.restoreStateFromMemento(caretaker.getMemento(1));
}
}
When to Use
- When you need to capture the state of an object for later restoration.
- When implementing undo/redo functionality.
- When you want to maintain the encapsulation of the object's state.
Advantages
- Preserves encapsulation by storing the object's state in a separate object.
- Facilitates undo/redo functionality without exposing object internals.
Disadvantages
- Can increase memory usage if the stored state is large or frequent snapshots are required.
- May add complexity to the codebase due to additional classes.