In this lesson, you will learn how to capture and restore system states by decoupling an object’s internal data from its external representation using a standardized trait-based approach.
The Problem: Encapsulation vs. Persistence
When we build complex systems, we often need to "save" the state of an object so we can roll back changes or serialize it to disk. However, exposing an object’s private fields to the outside world destroys encapsulation. The Memento Pattern solves this by creating a separate "Memento" struct that holds a snapshot of the state, ensuring that the main logic remains isolated from the storage format.
Implementing with Traits
To keep our system flexible, we define a trait that dictates how an object can produce and consume its own state.
trait Memento {
type Snapshot;
fn save(&self) -> Self::Snapshot;
fn restore(&mut self, snapshot: Self::Snapshot);
}
By using an Associated Type (type Snapshot), we allow different objects to define exactly what their state looks like without forcing a global serialization format. The Originator (the object being saved) manages its own internal data, while the Caretaker (the entity triggering the save) simply holds onto the Snapshot without needing to know what is inside it.
Example in Practice
Imagine a Document that tracks its text content. Instead of allowing external code to change the text directly, we use the Memento pattern:
struct Document {
content: String,
}
struct DocSnapshot(String);
impl Memento for Document {
type Snapshot = DocSnapshot;
fn save(&self) -> Self::Snapshot {
DocSnapshot(self.content.clone())
}
fn restore(&mut self, snapshot: Self::Snapshot) {
self.content = snapshot.0;
}
}
In this architecture, the Document remains the sole authority over its data. The DocSnapshot acts as a "black box" that the Caretaker stores. If the Document needs to revert to a previous state, it simply calls restore with the stored snapshot. This pattern is particularly powerful when combined with our previous work on Type-Safe Resource Lifecycle Management, as it ensures that state restoration only occurs when the system is in a valid, consistent phase.
Key Takeaway: The Memento pattern separates state representation from the object's internal logic, providing a clean, trait-based mechanism for serialization without violating encapsulation.