Recent from talks
Nothing was collected or created yet.
Memento pattern
View on WikipediaThe memento pattern is a software design pattern that exposes the private internal state of an object. One example of how this can be used is to restore an object to its previous state (undo via rollback), another is versioning, another is custom serialization.
The memento pattern is implemented with three objects: the originator, a caretaker and a memento. The originator is some object that has an internal state. The caretaker is going to do something to the originator, but wants to be able to undo the change. The caretaker first asks the originator for a memento object. Then it does whatever operation (or sequence of operations) it was going to do. To roll back to the state before the operations, it returns the memento object to the originator. The memento object itself is an opaque object (one which the caretaker cannot, or should not, change). When using this pattern, care should be taken if the originator may change other objects or resources—the memento pattern operates on a single object.
Classic examples of the memento pattern include a pseudorandom number generator (each consumer of the PRNG serves as a caretaker who can initialize the PRNG (the originator) with the same seed (the memento) to produce an identical sequence of pseudorandom numbers) and the state in a finite state machine.
Structure
[edit]UML class and sequence diagram
[edit]
In the above UML class diagram,
the Caretaker class refers to the Originator class
for saving (createMemento()) and restoring (restore(memento)) originator's internal state.
The Originator class implements
(1) createMemento() by creating and returning a Memento object that stores originator's current internal state
and
(2) restore(memento) by restoring state from the passed in Memento object.
The UML sequence diagram
shows the run-time interactions:
(1) Saving originator's internal state: The Caretaker object calls createMemento() on the Originator object,
which creates a Memento object, saves
its current internal state (setState()), and returns the Memento to the Caretaker.
(2) Restoring originator's internal state: The Caretaker calls restore(memento) on the Originator object and specifies the Memento object that stores the state that should be restored. The Originator gets the state (getState()) from the Memento to set its own state.
Java example
[edit]The following Java program illustrates the "undo" usage of the memento pattern.
package org.wikipedia.examples;
import java.util.ArrayList;
import java.util.List;
class Originator {
private String state;
// The class could also contain additional data that is not part of the
// state saved in the memento..
public void set(String state) {
this.state = state;
System.out.printf("Originator: Setting state to %s%n", state);
}
public Memento saveToMemento() {
System.out.println("Originator: Saving to Memento.");
return new Memento(this.state);
}
public void restoreFromMemento(Memento memento) {
this.state = memento.getSavedState();
System.out.printf("Originator: State after restoring from Memento: %s%n", state);
}
public static class Memento {
private final String state;
public Memento(String stateToSave) {
state = stateToSave;
}
// accessible by outer class only
private String getSavedState() {
return state;
}
}
}
class Caretaker {
public static void main(String[] args) {
List<Originator.Memento> savedStates = new ArrayList<Originator.Memento>();
Originator originator = new Originator();
originator.set("State1");
originator.set("State2");
savedStates.add(originator.saveToMemento());
originator.set("State3");
// We can request multiple mementos, and choose which one to roll back to.
savedStates.add(originator.saveToMemento());
originator.set("State4");
originator.restoreFromMemento(savedStates.get(1));
}
}
The output is:
Originator: Setting state to State1 Originator: Setting state to State2 Originator: Saving to Memento. Originator: Setting state to State3 Originator: Saving to Memento. Originator: Setting state to State4 Originator: State after restoring from Memento: State3
This example uses a String as the state, which is an immutable object in Java. In real-life scenarios the state will almost always be a mutable object, in which case a copy of the state must be made.
It must be said that the implementation shown has a drawback: it declares an internal class. It would be better if this memento strategy could apply to more than one originator.
There are mainly three other ways to achieve Memento:
- Serialization.
- A class declared in the same package.
- The object can also be accessed via a proxy, which can achieve any save/restore operation on the object.
C# example
[edit]The memento pattern allows one to capture the internal state of an object without violating encapsulation such that later one can undo/revert the changes if required. Here one can see that the memento object is actually used to revert the changes made in the object.
namespace Wikipedia.Examples;
class Memento
{
private readonly string _savedState;
private Memento(string stateToSave)
{
_savedState = stateToSave;
}
public class Originator
{
private string _state;
// The class could also contain additional data that is not part of the
// state saved in the memento.
public void Set(string state)
{
Console.WriteLine(f"Originator: Setting state to {state}");
_state = state;
}
public Memento SaveToMemento()
{
Console.WriteLine("Originator: Saving to Memento.");
return new Memento(_state);
}
public void RestoreFromMemento(Memento memento)
{
_state = memento.savedState;
Console.WriteLine(f"Originator: State after restoring from Memento: {_state}");
}
}
}
class Caretaker
{
static void Main(string[] args)
{
List<Memento> savedStates = new();
Memento.Originator originator = new();
originator.Set("State1");
originator.Set("State2");
savedStates.Add(originator.SaveToMemento());
originator.Set("State3");
// We can request multiple mementos, and choose which one to roll back to.
savedStates.Add(originator.SaveToMemento());
originator.Set("State4");
originator.RestoreFromMemento(savedStates[1]);
}
}
Python example
[edit]"""
Memento pattern example.
"""
class Originator:
state: str = ""
def set(self, state: str) -> None:
print(f"Originator: Setting state to {state}")
self.state = state
def save_to_memento(self) -> "Memento":
return self.Memento(self.state)
def restore_from_memento(self, memento: "Memento") -> None:
self.state = memento.get_saved_state()
print(f"Originator: State after restoring from Memento: {self.state}")
class Memento:
state: str
def __init__(self, state: str) -> None:
self.state = state
def get_saved_state(self) -> str:
return self.state
saved_states: list[Memento] = []
originator: Originator = Originator()
originator.set("State1")
originator.set("State2")
saved_states.append(originator.save_to_memento())
originator.set("State3")
saved_states.append(originator.save_to_memento())
originator.set("State4")
originator.restore_from_memento(saved_states[1])
JavaScript example
[edit]// The Memento pattern is used to save and restore the state of an object.
// A memento is a snapshot of an object's state.
let Memento = {// Namespace: Memento
savedState : null, // The saved state of the object.
save : function(state) { // Save the state of an object.
this.savedState = state;
},
restore : function() { // Restore the state of an object.
return this.savedState;
}
};
// The Originator is the object that creates the memento.
// defines a method for saving the state inside a memento.
let Originator = {// Namespace: Originator
state : null, // The state to be stored
// Creates a new originator with an initial state of null
createMemento : function() {
return {
state : this.state // The state is copied to the memento.
};
},
setMemento : function(memento) { // Sets the state of the originator from a memento
this.state = memento.state;
}
};
// The Caretaker stores mementos of the objects and
// provides operations to retrieve them.
let Caretaker = {// Namespace: Caretaker
mementos : [], // The mementos of the objects.
addMemento : function(memento) { // Add a memento to the collection.
this.mementos.push(memento);
},
getMemento : function(index) { // Get a memento from the collection.
return this.mementos[index];
}
};
let action_step = "Foo"; // The action to be executed/the object state to be stored.
let action_step_2 = "Bar"; // The action to be executed/the object state to be stored.
// set the initial state
Originator.state = action_step;
Caretaker.addMemento(Originator.createMemento());// save the state to the history
console.log("Initial State: " + Originator.state); // Foo
// change the state
Originator.state = action_step_2;
Caretaker.addMemento(Originator.createMemento()); // save the state to the history
console.log("State After Change: " + Originator.state); // Bar
// restore the first state - undo
Originator.setMemento(Caretaker.getMemento(0));
console.log("State After Undo: " + Originator.state); // Foo
// restore the second state - redo
Originator.setMemento(Caretaker.getMemento(1));
console.log("State After Redo: " + Originator.state); // Bar
References
[edit]- ^ "The Memento design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.
External links
[edit]- Description of Memento Pattern in Ada
- Memento UML Class Diagram with C# and .NET code samples
- SourceMaking Tutorial
- Memento Design Pattern using Java
Memento pattern
View on GrokipediaOverview
Definition and Intent
The Memento pattern is a behavioral software design pattern that enables the capture and externalization of an object's internal state without violating encapsulation, allowing the object to be restored to that state later.[2] This approach treats the saved state as an opaque token, preventing unauthorized access to sensitive internal details while supporting reliable state management.[2] The primary intent of the Memento pattern is to facilitate operations like undo, redo, or versioning by externalizing an object's state in a controlled manner, ensuring that the restoration process does not compromise the object's integrity or reveal its implementation.[2] By design, it addresses the challenge of preserving state snapshots for deferred use, such as in interactive applications where users need to revert changes without exposing the underlying data structure.[2] Encapsulation is maintained through the use of a dedicated memento object that acts as an intermediary: it stores the state in a form accessible only to the originating object, while external components, such as a caretaker, interact with it via a limited interface that hides the specifics of the stored data.[2] This intermediary role ensures that state transfer remains secure and modular, aligning with object-oriented principles of information hiding.[2]Historical Context
The Memento pattern was formally introduced in the influential 1994 book Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, collectively known as the Gang of Four (GoF).[2] This work cataloged 23 reusable solutions to common problems in object-oriented software design, with the Memento classified among the behavioral patterns for its focus on object communication and responsibility assignment.[2] The pattern's name derives from the Latin word memento, meaning "remember," symbolizing a token or keepsake that preserves an object's prior state, much like a memento in storytelling or theater serves as a reminder of past events or conditions.[2] In the GoF framework, it addresses the need to externalize internal state snapshots without compromising encapsulation, drawing from practical requirements in interactive applications like graphical editors.[2] Although formalized in 1994, precursors to the Memento pattern emerged in late-1980s object-oriented programming discussions, particularly around state management in early interactive systems and languages like Smalltalk, where mechanisms for capturing and restoring object states supported incremental development and error recovery.[3] The pattern saw adoption in 1990s GUI frameworks to enable undo operations, allowing applications to revert user actions by reloading saved states without exposing underlying object details.[2] A key milestone was its integration into the GoF catalog, which standardized the pattern and spurred its use across software engineering; this legacy aligns with state persistence features in modern languages, such as Java's Serializable interface (introduced in JDK 1.1 in 1997), which can be used to implement externalization of object states while supporting encapsulation goals similar to those of the Memento pattern.[4]Motivation and Applicability
Problem It Solves
The Memento pattern addresses the challenge of capturing and externalizing an object's internal state for later restoration without compromising encapsulation, a critical requirement in object-oriented design where direct access to private fields could lead to tight coupling between components or unintended modifications. This problem arises in scenarios requiring state preservation, such as implementing undo mechanisms, where an application's core objects must maintain their integrity while allowing external entities—like a user interface or transaction manager—to store and retrieve snapshots of their state. Without a structured approach, developers risk exposing sensitive implementation details, potentially introducing security vulnerabilities or making the system brittle to future changes.[5][1] A classic example occurs in a text editor application, where users expect to undo typing or editing actions by reverting the document to its prior state, including not only the text content but also cursor position and formatting attributes. To achieve this, the editor (the originator object) must create a snapshot of its internal state at key moments, but providing public methods to access or set these private fields would violate encapsulation principles outlined in foundational design literature, allowing external code to inadvertently alter the object's consistency. This encapsulation breach could propagate errors across the system, as changes to the editor's internals might require updates to all dependent components.[5][1] Beyond editors, the pattern tackles related issues in areas like simulation software for versioning object states during iterative computations, where partial exposure of internal data might compromise the simulation's accuracy or lead to data integrity failures. Similarly, in database systems supporting transaction rollbacks, preserving the pre-transaction state of complex entities without revealing proprietary structures is essential to prevent cascading failures or unauthorized access. These contexts highlight the need for a mechanism that isolates state storage from the object's core logic, ensuring that external caregivers can manage snapshots without deep knowledge of the internals.[5][1] Alternative approaches, such as direct serialization of objects or implementing ad-hoc getter and setter methods for all private fields, often fail because they either bypass encapsulation entirely—exposing the object's fragile internals to external modification—or increase maintenance overhead by requiring extensive refactoring whenever the internal structure evolves. For instance, public serialization might serialize unnecessary or sensitive data, raising privacy concerns, while proliferating accessors creates a facade of simplicity that ties the object's evolution to its consumers, leading to higher coupling and reduced reusability. The Memento pattern circumvents these pitfalls by designating a dedicated, opaque container for state, accessible only by the originator itself.[5][1]When to Use
The Memento pattern is particularly suitable for implementing undo and redo functionality in interactive applications, such as text editors or graphical user interfaces, where users need to revert to previous states without compromising the object's internal representation. It also supports transaction rollbacks in business logic systems, allowing safe restoration of an object's state after a series of operations, as exemplified in command-based histories that require point-in-time recovery.[6][1] This pattern finds ideal application in contexts where an object's state undergoes frequent modifications and requires restoration to a prior snapshot, such as in simulation software or database transaction managers that maintain audit trails. It ensures that external entities can capture and reinstate the state without gaining direct access to sensitive internal details, thereby preserving encapsulation while enabling features like state checkpointing in constraint solvers or iterative algorithms.[6][1] To determine applicability, consider the following checklist derived from the pattern's core intent:- The object possesses a complex or voluminous internal state that cannot be easily exposed or copied via public interfaces.
- The caretaker (e.g., a controller or history manager) should not need to comprehend or manipulate the full state details, relying instead on opaque access.
- A distinction between narrow (public, limited) and wide (private, comprehensive) interfaces for the memento is feasible, allowing the originator full control over state serialization while restricting external views.
Components and Structure
Participants and Responsibilities
The Memento pattern involves three primary participants: the Originator, the Memento, and the Caretaker, each with distinct roles in capturing, storing, and restoring an object's internal state while preserving encapsulation.[1][7][8] The Originator is the core object whose state requires preservation for potential restoration, such as in undo operations or state checkpoints. It is responsible for creating a Memento that encapsulates a snapshot of its current internal state by copying the state and for restoring its state from a provided Memento when needed, ensuring that the Memento accurately reflects and reinstates the Originator's data without exposing implementation details to external entities.[1][7][8] The Memento serves as an opaque value object that stores the Originator's state in a protected manner, acting as a capsule that hides the details from unauthorized access. It provides a narrow interface to the Caretaker that offers no access to the internal state, while offering a wide interface exclusively to the Originator for full access to the stored data. To enhance safety, the Memento is often designed to be immutable once created, preventing unintended alterations during storage.[1][7][8] The Caretaker manages the lifecycle of Mementos without ever directly accessing or altering the encapsulated state, thereby maintaining the Originator's privacy. It is tasked with deciding when to request a Memento from the Originator for saving—such as pushing it onto a stack for historical tracking—and when to pass a Memento back to the Originator for state restoration. This participant orchestrates the overall process, such as implementing undo/redo functionality, but remains oblivious to the specifics of the state to uphold encapsulation principles.[1][7][8]UML Diagrams
The UML class diagram for the Memento pattern illustrates the static structure involving three primary participants: the Originator, Memento, and Caretaker. The Originator class includes methods such ascreateMemento() to generate a snapshot of its internal state and setMemento(memento) to restore from a provided Memento; its internal state (e.g., a private field like state) is not directly accessible to external classes. The Memento class features a private state field encapsulating the Originator's data, along with getState() and setState(state) methods that form the wide interface accessible only to the Originator, while the narrow interface provides no methods for accessing the internal state, making it opaque to the Caretaker. The Caretaker class manages Mementos through methods like add(memento) and getMemento(), without access to the internal state. Relationships are depicted as associations: the Originator creates and uses the Memento (solid line with arrow for creation), and the Caretaker holds the Memento (composition or aggregation). Private visibility is denoted by minus signs (-) on the state field to emphasize encapsulation, while public methods use plus signs (+); no inheritance is involved, but dependencies may be shown as dotted lines if the Memento references the Originator for restoration.[1]
This class diagram highlights the narrow/wide interface dichotomy central to the pattern: the narrow interface restricts the Caretaker to non-sensitive operations, preventing unintended state exposure, whereas the wide interface allows the Originator full access to restore its exact prior state, preserving object-oriented encapsulation as defined in the original pattern description.
The sequence diagram depicts the dynamic interactions for saving and restoring state. It begins with the Caretaker invoking createMemento() on the Originator, which internally constructs a new Memento object by copying its current state via the constructor or setter methods. The Originator then passes this Memento to the Caretaker for storage (e.g., via add(memento)). Later, to restore, the Caretaker retrieves a Memento (e.g., via getMemento()) and calls setMemento(memento) on the Originator, which uses the wide interface to update its private state from the Memento's encapsulated data. Lifelines represent the participants vertically, with activation bars indicating method execution; synchronous messages are solid arrows, and the flow emphasizes the Caretaker's role as an intermediary without state knowledge.[1]
A textual representation of the sequence diagram is as follows:
Participant: Caretaker Originator Memento
| | |
|---createMemento()-->| |
| |---new()-->|
|<--memento----| |
|---add(memento)---------->|
| | |
|<--getMemento()-----------|
|---setMemento(m)-->| |
| |<--state--|
| | |
Participant: Caretaker Originator Memento
| | |
|---createMemento()-->| |
| |---new()-->|
|<--memento----| |
|---add(memento)---------->|
| | |
|<--getMemento()-----------|
|---setMemento(m)-->| |
| |<--state--|
| | |
Implementation
Key Considerations
When implementing the Memento pattern, encapsulation is a primary concern to prevent unauthorized access to the Originator's internal state. One effective strategy in object-oriented languages like Java is to define the Memento as a non-public inner class within the Originator, which allows the Originator full access to the Memento's fields while restricting the Caretaker to only essential metadata, such as a version identifier. This approach maintains strict privacy of the state without exposing it through public interfaces. Alternatively, an interface can be used for the Caretaker's view of the Memento, exposing only read-only properties, while the full Memento class remains package-private or otherwise limited.[1][7] Handling immutable versus mutable states requires careful design to ensure the integrity of saved snapshots. Mementos should ideally be immutable, with state set only through constructors and no setter methods, to prevent accidental modifications after creation and to avoid side effects during restoration. For mutable states in complex Originator objects, such as those containing collections or nested objects, a shallow copy may suffice for simple primitives but often leads to pitfalls like unintended shared references; in these cases, implementing deep copies during Memento creation is necessary to fully isolate the historical state.[1][9] Memory management poses significant trade-offs, particularly when storing multiple Mementos for features like undo histories. Accumulating a stack or list of Mementos in the Caretaker can consume substantial RAM, especially for large or frequently updated Originator states, potentially leading to performance degradation or out-of-memory errors in resource-constrained environments. To mitigate this, developers should monitor the Caretaker's lifecycle and explicitly discard obsolete Mementos to aid garbage collection, and for very large objects, consider optimizations like storing only deltas or using lazy loading to defer full state reconstruction until restoration.[1] Thread safety must be addressed if Mementos are created, stored, or restored in concurrent scenarios, as unsynchronized access could corrupt the state or lead to inconsistent snapshots. Since Mementos are typically not shared across threads but rather passed between Originator and Caretaker, synchronization—such as using locks around create/restore operations or making Mementos thread-local—ensures atomicity without overcomplicating the pattern. In multi-threaded applications, avoiding concurrent modifications to the same Originator instance during Memento operations is crucial to prevent race conditions.[1][8] The pattern supports variations like internal and external Memento configurations to balance encapsulation and flexibility. In the internal variation, the Memento is tightly coupled as a nested class, enhancing privacy but reducing reusability across different Originators. The external variation uses a separate, interface-driven Memento class, allowing broader applicability but requiring additional safeguards, such as friend-like access controls, to protect the state from external tampering. These choices depend on the application's needs for modularity versus security.[1]Pseudocode Example
The Memento pattern can be illustrated through abstract pseudocode that captures the essential interactions among the Originator, Memento, and Caretaker classes, emphasizing the encapsulation of state without exposing internal details.Originator Pseudocode
The Originator maintains the current state and provides methods to create a Memento capturing that state, as well as to restore from a Memento using a wide interface that allows full access to the encapsulated data.class Originator {
private state; // Internal state to be saved/restored
method setState(newState) {
this.state = newState;
}
method getState() {
return this.state;
}
// Creates a new Memento with a copy of the current state (narrow interface exposed to Caretaker)
method createMemento() {
return new Memento(this.getState());
}
// Restores state from Memento using wide interface (full access to Memento's private state)
method restoreFromMemento(memento) {
this.state = memento.getFullState(); // Direct access to internal state copy
}
}
class Originator {
private state; // Internal state to be saved/restored
method setState(newState) {
this.state = newState;
}
method getState() {
return this.state;
}
// Creates a new Memento with a copy of the current state (narrow interface exposed to Caretaker)
method createMemento() {
return new Memento(this.getState());
}
// Restores state from Memento using wide interface (full access to Memento's private state)
method restoreFromMemento(memento) {
this.state = memento.getFullState(); // Direct access to internal state copy
}
}
Memento Pseudocode
The Memento serves as an opaque value object that stores the Originator's state. It provides a narrow interface to the Caretaker (limited to basic storage/retrieval) and a wide interface to the Originator for restoration.class Memento {
private fullState; // Copy of Originator's state (immutable)
constructor(stateCopy) {
this.fullState = stateCopy; // Encapsulate the state
}
// Narrow interface: Caretaker can only retrieve a limited view (e.g., metadata), not full state
method getStateMetadata() {
return { timestamp: currentTime(), size: sizeof(this.fullState) }; // Example limited info
}
// Wide interface: Only Originator can access the full state for restoration
method getFullState() {
return this.fullState; // Full access granted to Originator
}
}
class Memento {
private fullState; // Copy of Originator's state (immutable)
constructor(stateCopy) {
this.fullState = stateCopy; // Encapsulate the state
}
// Narrow interface: Caretaker can only retrieve a limited view (e.g., metadata), not full state
method getStateMetadata() {
return { timestamp: currentTime(), size: sizeof(this.fullState) }; // Example limited info
}
// Wide interface: Only Originator can access the full state for restoration
method getFullState() {
return this.fullState; // Full access granted to Originator
}
}
Caretaker Pseudocode
The Caretaker manages Mementos without knowledge of their internal structure, typically using a stack for undo operations via the narrow interface.class Caretaker {
private mementoStack = []; // Stack to hold Mementos for history
method saveMemento(originator) {
memento = originator.createMemento();
this.mementoStack.push(memento); // Store via narrow interface
}
method restoreMemento(originator) {
if (!this.mementoStack.isEmpty()) {
lastMemento = this.mementoStack.pop();
originator.restoreFromMemento(lastMemento); // Trigger restoration
}
}
}
class Caretaker {
private mementoStack = []; // Stack to hold Mementos for history
method saveMemento(originator) {
memento = originator.createMemento();
this.mementoStack.push(memento); // Store via narrow interface
}
method restoreMemento(originator) {
if (!this.mementoStack.isEmpty()) {
lastMemento = this.mementoStack.pop();
originator.restoreFromMemento(lastMemento); // Trigger restoration
}
}
}
Full Example Flow
To demonstrate the pattern in action, consider an initialization and usage sequence where the Originator's state changes over operations, with saves and restores managed by the Caretaker. This flow highlights how the narrow interface protects the state from external modification while allowing seamless undo functionality.// Initialize components
originator = new Originator();
originator.setState("Initial state");
caretaker = new Caretaker();
// Perform initial save
caretaker.saveMemento(originator); // Captures "Initial state" in Memento
// Modify state
originator.setState("Modified state 1");
caretaker.saveMemento(originator); // Captures "Modified state 1"
// Further modification
originator.setState("Modified state 2");
// Restore to previous state (undo last change)
caretaker.restoreMemento(originator); // Restores "Modified state 1" using wide interface
// Restore further (undo again)
caretaker.restoreMemento(originator); // Restores "Initial state"
// Initialize components
originator = new Originator();
originator.setState("Initial state");
caretaker = new Caretaker();
// Perform initial save
caretaker.saveMemento(originator); // Captures "Initial state" in Memento
// Modify state
originator.setState("Modified state 1");
caretaker.saveMemento(originator); // Captures "Modified state 1"
// Further modification
originator.setState("Modified state 2");
// Restore to previous state (undo last change)
caretaker.restoreMemento(originator); // Restores "Modified state 1" using wide interface
// Restore further (undo again)
caretaker.restoreMemento(originator); // Restores "Initial state"
createMemento() returns a Memento that hides fullState from the Caretaker) and wide interface (e.g., getFullState() is accessible only by the Originator to prevent encapsulation breaches).
Language-Specific Examples
Java Implementation
The Memento pattern in Java is typically implemented using classes that leverage the language's strong encapsulation features, such as private fields and inner classes, to protect the originator's internal state while allowing controlled access for restoration. This approach aligns with the pattern's description in the seminal work on design patterns, where the memento provides a narrow interface to the caretaker and a wide interface to the originator. A common example simulates a simple text editor's undo functionality, using aStringBuilder for mutable state.
To enforce access control, the Memento is defined as a private inner class within the Originator (here, TextEditor), ensuring that only the originator can create or fully access the memento's state, while the Caretaker receives an opaque reference via a public interface. The Caretaker maintains a stack of mementos using a List for multiple undos.
import java.util.ArrayList;
import java.util.List;
// Public interface for narrow access by Caretaker
interface Memento {
// No methods exposed; opaque to Caretaker
}
// Originator
class TextEditor {
private StringBuilder text = new StringBuilder();
// Method to add text
public void write(String input) {
text.append(input);
}
// Save current state as Memento
public Memento save() {
return new ConcreteMemento(text.toString());
}
// Restore from Memento
public void restore(Memento memento) {
if (memento instanceof ConcreteMemento) {
text = new StringBuilder(((ConcreteMemento) memento).state);
}
}
// Get current text (for demonstration)
public String getText() {
return text.toString();
}
// Private inner class for wide interface (full state access)
private static class ConcreteMemento implements Memento {
private final String state;
ConcreteMemento(String state) {
this.state = state;
}
}
}
// Caretaker
class History {
private List<Memento> mementos = new ArrayList<>();
public void push(Memento memento) {
mementos.add(memento);
}
public [boolean](/page/Boolean) [undo](/page/Undo)() {
if (mementos.isEmpty()) {
return false;
}
mementos.remove(mementos.size() - 1);
return true;
}
public Memento pop() {
if (mementos.isEmpty()) {
return null;
}
return mementos.remove(mementos.size() - 1);
}
// Restore to a specific state (e.g., last saved)
public void restoreLast(TextEditor editor) {
if (!mementos.isEmpty()) {
Memento last = mementos.get(mementos.size() - 1);
editor.restore(last);
}
}
}
// Demonstration
public class MementoDemo {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
[History](/page/History) history = new History();
editor.write("Hello, ");
System.out.println("After 'Hello, ': " + editor.getText());
history.push(editor.save()); // Save state 1
editor.write("World!");
System.out.println("After 'World!': " + editor.getText());
history.push(editor.save()); // Save state 2
editor.write(" How are you?");
System.out.println("After ' How are you?': " + editor.getText());
// Undo to state 2
history.restoreLast(editor);
System.out.println("After undo to state 2: " + editor.getText());
// Undo to state 1
history.pop(); // Remove state 2
history.restoreLast(editor);
System.out.println("After undo to state 1: " + editor.getText());
}
}
import java.util.ArrayList;
import java.util.List;
// Public interface for narrow access by Caretaker
interface Memento {
// No methods exposed; opaque to Caretaker
}
// Originator
class TextEditor {
private StringBuilder text = new StringBuilder();
// Method to add text
public void write(String input) {
text.append(input);
}
// Save current state as Memento
public Memento save() {
return new ConcreteMemento(text.toString());
}
// Restore from Memento
public void restore(Memento memento) {
if (memento instanceof ConcreteMemento) {
text = new StringBuilder(((ConcreteMemento) memento).state);
}
}
// Get current text (for demonstration)
public String getText() {
return text.toString();
}
// Private inner class for wide interface (full state access)
private static class ConcreteMemento implements Memento {
private final String state;
ConcreteMemento(String state) {
this.state = state;
}
}
}
// Caretaker
class History {
private List<Memento> mementos = new ArrayList<>();
public void push(Memento memento) {
mementos.add(memento);
}
public [boolean](/page/Boolean) [undo](/page/Undo)() {
if (mementos.isEmpty()) {
return false;
}
mementos.remove(mementos.size() - 1);
return true;
}
public Memento pop() {
if (mementos.isEmpty()) {
return null;
}
return mementos.remove(mementos.size() - 1);
}
// Restore to a specific state (e.g., last saved)
public void restoreLast(TextEditor editor) {
if (!mementos.isEmpty()) {
Memento last = mementos.get(mementos.size() - 1);
editor.restore(last);
}
}
}
// Demonstration
public class MementoDemo {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
[History](/page/History) history = new History();
editor.write("Hello, ");
System.out.println("After 'Hello, ': " + editor.getText());
history.push(editor.save()); // Save state 1
editor.write("World!");
System.out.println("After 'World!': " + editor.getText());
history.push(editor.save()); // Save state 2
editor.write(" How are you?");
System.out.println("After ' How are you?': " + editor.getText());
// Undo to state 2
history.restoreLast(editor);
System.out.println("After undo to state 2: " + editor.getText());
// Undo to state 1
history.pop(); // Remove state 2
history.restoreLast(editor);
System.out.println("After undo to state 1: " + editor.getText());
}
}
ConcreteMemento class can implement the Serializable interface, allowing mementos to be written to disk or transmitted, though this requires marking the state field as transient if sensitive and handling serialization of the StringBuilder content appropriately. In the demonstration above, running the main method outputs the progressive state changes and undos, simulating a text editor where "Hello, World!" and then "Hello, " are restored step-by-step, illustrating the pattern's role in reversible operations without exposing internal details.
Python Implementation
The Memento pattern in Python leverages the language's dynamic typing and convention-based privacy (via single underscore prefix for attributes) to encapsulate object state without strict access modifiers, allowing flexible snapshot management through classes rather than inner classes or modules alone. A practical example illustrates this with a simple calculator as the Originator, where the state represents the current numerical value, enabling operations like addition while supporting rollback via mementos stored in a Caretaker. This approach aligns with Python's emphasis on readability and simplicity, avoiding boilerplate for visibility control.[10] The Originator class maintains a private_value attribute and provides methods to perform calculations, create a memento capturing the current state, and restore from a memento. The Memento class holds the state privately, exposing it only to the Originator. The Caretaker manages a stack of mementos for undo operations.
class Memento:
"""Holds the state of the Originator."""
def __init__(self, state):
self._state = state
def get_state(self):
return self._state
class CalculatorOriginator:
"""Maintains the calculator state and operations."""
def __init__(self, initial_value=0):
self._value = initial_value
def add(self, amount):
self._value += amount
print(f"Current value: {self._value}")
def create_memento(self):
return Memento(self._value)
def set_memento(self, memento):
self._value = memento.get_state()
print(f"Restored value: {self._value}")
class Caretaker:
"""Manages mementos for undo functionality."""
def __init__(self):
self._mementos = []
def save(self, memento):
self._mementos.append(memento)
print("State saved.")
def undo(self):
if self._mementos:
restored_memento = self._mementos.pop()
print("Undoing to previous state.")
return restored_memento
return None
class Memento:
"""Holds the state of the Originator."""
def __init__(self, state):
self._state = state
def get_state(self):
return self._state
class CalculatorOriginator:
"""Maintains the calculator state and operations."""
def __init__(self, initial_value=0):
self._value = initial_value
def add(self, amount):
self._value += amount
print(f"Current value: {self._value}")
def create_memento(self):
return Memento(self._value)
def set_memento(self, memento):
self._value = memento.get_state()
print(f"Restored value: {self._value}")
class Caretaker:
"""Manages mementos for undo functionality."""
def __init__(self):
self._mementos = []
def save(self, memento):
self._mementos.append(memento)
print("State saved.")
def undo(self):
if self._mementos:
restored_memento = self._mementos.pop()
print("Undoing to previous state.")
return restored_memento
return None
caretaker.[undo](/page/Undo)() returns the memento, which is then passed to originator.set_memento(memento).[10][11]
