Memento
The Memento pattern allows saving and restoring an object’s internal state without violating encapsulation. It achieves this by creating a separate “memento” object that holds the state, which the originator can create and hand to a caretaker for storage. The caretaker is responsible for holding mementos but cannot inspect or alter their contents.
This pattern is particularly useful in scenarios requiring undo/redo functionality, transaction management, or the ability to revert to previous states without exposing the object’s internal details. It supports the principle of information hiding by ensuring the object’s internal representation remains private.
Usage
The Memento pattern finds widespread use in applications where maintaining historical states is crucial. Common scenarios include:
- Undo/Redo Systems: Text editors, image manipulation software, and game engines all utilize mementos to implement undo and redo features.
- Transaction Management: Database systems and financial applications use mementos to save the state before a transaction and roll back to that state if the transaction fails.
- Checkpoints: Game saving mechanisms often employ mementos to store the game’s state at specific points, allowing players to resume from those checkpoints.
- Version Control: While more complex, the underlying principle of storing previous states is similar to version control systems.
Examples
-
Git (Version Control): Git utilizes a more advanced version of the Memento pattern in its commits. Each commit essentially acts as a memento, storing a snapshot of the entire project’s state at a specific point in time. The caretaker is Git itself, managed by the user. While not a direct one-to-one Memento implementation because of merging and branching, the core idea of saving and restoring states remains.
-
Java Serialized Object Stream: Java’s
Serializableinterface andObjectOutputStream/ObjectInputStreamclasses provide a built-in mechanism for serializing and deserializing objects. Serializing an object can be viewed as creating a memento (a byte stream representing the object’s state), and deserializing restores the object to that prior state. TheObjectOutputStreamplays the role of the caretaker, storing the serialized data. This is a simple automatic implementation of the pattern.
Specimens
15 implementationsThe Memento pattern captures and externalizes an object’s internal state so that the object can be restored to this state later, even if the object is modified or destroyed. It consists of three parts: the Originator, the Memento, and the Caretaker. The Originator holds the state, the Memento is an immutable snapshot of that state, and the Caretaker is responsible for storing and retrieving Mementos without directly accessing the Originator’s state.
This Dart implementation uses classes to represent each part. The Editor is the Originator, holding the text and providing methods to set and save its state. The TextSnapshot is the Memento, storing the text immutably. The History class acts as the Caretaker, managing a list of TextSnapshot objects. Dart’s immutability features (using final) are leveraged in the TextSnapshot to ensure the state remains consistent. This approach aligns with Dart’s object-oriented nature and promotes encapsulation.
class TextSnapshot {
final String text;
TextSnapshot(this.text);
String getText() => text;
}
class Editor {
String _text = "";
String getText() => _text;
void setText(String text) {
_text = text;
}
TextSnapshot save() {
return TextSnapshot(_text);
}
void restore(TextSnapshot snapshot) {
_text = snapshot.getText();
}
}
class History {
List<TextSnapshot> _snapshots = [];
void push(TextSnapshot snapshot) {
_snapshots.add(snapshot);
}
TextSnapshot pop() {
if (_snapshots.isEmpty) {
return null;
}
return _snapshots.removeLast();
}
}
void main() {
final editor = Editor();
final history = History();
editor.setText("Hello");
history.push(editor.save());
editor.setText("World");
history.push(editor.save());
print("Current text: ${editor.getText()}"); // Output: Current text: World
final snapshot = history.pop();
editor.restore(snapshot!);
print("Restored text: ${editor.getText()}"); // Output: Restored text: Hello
final snapshot2 = history.pop();
editor.restore(snapshot2!);
print("Restored text: ${editor.getText()}"); // Output: Restored text:
}
The Memento pattern captures and externalizes an object’s internal state so that the object can be restored to this state later, even if the object itself is modified or destroyed. This is crucial for implementing undo/redo functionality, transaction management, or versioning.
The Scala code implements the Memento pattern by defining a Memento case class to hold the object’s state (a string in this case), and a Originator class that creates mementos and restores itself from them. A Caretaker class manages the storage of mementos without exposing their internal state. Scala’s immutability and case classes make this pattern concise and safe, since Mementos are naturally immutable snapshots of the Originator’s state, avoiding accidental modification. This adheres to functional programming principles commonly used in Scala.
// Memento
case class Memento(state: String)
// Originator
class Originator(initialState: String) {
private var state: String = initialState
def setState(newState: String): Unit = {
state = newState
}
def getState: String = state
def save(): Memento = Memento(state)
def restore(memento: Memento): Unit = {
this.state = memento.state
}
}
// Caretaker
class Caretaker(private var mementos: List[Memento] = Nil) {
def addMemento(memento: Memento): Unit = {
mementos = memento :: mementos
}
def getMemento(index: Int): Option[Memento] = {
mementos.lift(index)
}
}
// Example Usage (for completeness - not essential for pattern)
object MementoExample {
def main(args: Array[String]): Unit = {
val originator = new Originator("Initial State")
val caretaker = new Caretaker()
caretaker.addMemento(originator.save())
originator.setState("State 1")
caretaker.addMemento(originator.save())
originator.setState("State 2")
println(originator.getState) // Output: State 2
// Restore to the first saved state
originator.restore(caretaker.getMemento(0).get)
println(originator.getState) // Output: Initial State
}
}
The Memento pattern is a behavioral pattern that captures and externalizes the internal state of an object without violating encapsulation. It allows restoring an object to its previous state (saving and loading states). This implementation uses a Memento class to hold the state, an Originator class whose state is saved, and a Caretaker to manage the history of Mementos. PHP’s object-oriented nature makes this design readily expressible. We leverage properties for state storage and methods for state manipulation and retrieval, keeping the internal state protected and manageable.
<?php
/**
* Memento: Holds a snapshot of the Originator's state.
*/
class Memento
{
private $state;
public function __construct(string $state)
{
$this->state = $state;
}
public function getState(): string
{
return $this->state;
}
}
/**
* Originator: The object whose state is to be saved and restored.
*/
class Originator
{
private $state;
public function __construct(string $initialState)
{
$this->state = $initialState;
}
public function setState(string $state): void
{
$this->state = $state;
}
public function getState(): string
{
return $this->state;
}
public function createMemento(): Memento
{
return new Memento($this->state);
}
public function restoreMemento(Memento $memento): void
{
$this->state = $memento->getState();
}
}
/**
* Caretaker: Manages the Mementos, but doesn't access the state within them.
*/
class Caretaker
{
private $mementos = [];
public function addMemento(Memento $memento): void
{
$this->mementos[] = $memento;
}
public function getMemento(int $index): ?Memento
{
return $this->mementos[$index] ?? null;
}
}
// Example Usage
$originator = new Originator("Initial State");
$caretaker = new Caretaker();
$caretaker->addMemento($originator->createMemento()); // Save State 1
$originator->setState("State 2");
$caretaker->addMemento($originator->createMemento()); // Save State 2
$originator->setState("State 3");
$caretaker->addMemento($originator->createMemento()); // Save State 3
echo "Current State: " . $originator->getState() . "\n"; // Output: State 3
// Restore to State 2
$originator->restoreMemento($caretaker->getMemento(1));
echo "Restored State: " . $originator->getState() . "\n"; // Output: State 2
?>
The Memento pattern captures and externalizes an object’s internal state so that the object can be restored to this state later, even if the object itself is modified or destroyed. This allows for “undo” operations or saving/restoring progress without violating encapsulation. My Ruby implementation uses a Memento class to hold the state, an Originator class whose state is saved and restored, and a Caretaker class to manage Mementos without accessing the originator’s state directly. It leverages Ruby’s open classes and simple object construction for conciseness, fitting the language’s dynamic and expressive nature.
# frozen_string_literal: true
# Memento: Holds the state of the Originator.
class Memento
attr_reader :state
def initialize(state)
@state = state
end
end
# Originator: Contains the state to be saved and restored.
class Originator
attr_accessor :state
def initialize(initial_state)
@state = initial_state
end
def create_memento
Memento.new(@state)
end
def restore_memento(memento)
@state = memento.state
end
end
# Caretaker: Manages Mementos without accessing the Originator’s state.
class Caretaker
attr_accessor :memento
def initialize
@memento = nil
end
def save_memento(originator)
@memento = originator.create_memento
end
def restore_memento(originator)
originator.restore_memento(@memento) if @memento
end
end
# Example usage:
if __FILE__ == $0
originator = Originator.new("Initial State")
caretaker = Caretaker.new
puts "Initial State: #{originator.state}"
caretaker.save_memento(originator)
originator.state = "New State"
puts "New State: #{originator.state}"
caretaker.restore_memento(originator)
puts "Restored State: #{originator.state}"
end
The Memento pattern is a behavioral design pattern that allows capturing and externalizing the internal state of an object without violating encapsulation. This is useful for implementing undo/redo functionality or saving/restoring object states. The pattern defines three roles: the Originator holds the state, the Memento stores the state, and the Caretaker manages Memento objects. The Originator creates a Memento representing its current state, and the Caretaker stores this Memento. The Originator can then restore its state from the Memento.
In this Swift implementation, Editor is the Originator, Snapshot is the Memento, and History is the Caretaker. Snapshot is a struct to ensure immutability of saved states, a common practice in Swift. The History stores Snapshots to allow the editor’s state to be restored at different points in time. Using structs for Snapshot leverages Swift’s value semantics for safe state storage.
// MARK: - Memento Pattern in Swift
// 1. Memento
struct Snapshot {
let state: String
}
// 2. Originator
class Editor {
private var state: String = ""
func type(input: String) {
state = state + input
print("Typed: \(input), Current State: \(state)")
}
func getState() -> String {
return state
}
func restore(from snapshot: Snapshot) {
state = snapshot.state
print("Restored to state: \(state)")
}
func createSnapshot() -> Snapshot {
return Snapshot(state: state)
}
}
// 3. Caretaker
class History {
private var snapshots: [Snapshot] = []
func push(snapshot: Snapshot) {
snapshots.append(snapshot)
}
func pop() -> Snapshot? {
return snapshots.popLast()
}
}
// Example Usage:
let editor = Editor()
let history = History()
editor.type(input: "Hello, ")
history.push(snapshot: editor.createSnapshot())
editor.type(input: "World!")
history.push(snapshot: editor.createSnapshot())
print("\nUndoing...")
if let snapshot = history.pop() {
editor.restore(from: snapshot)
}
print("\nUndoing...")
if let snapshot = history.pop() {
editor.restore(from: snapshot)
}
The Memento pattern is a behavioral pattern that allows you to capture and externalize the internal state of an object without violating encapsulation. It’s often used for implementing undo/redo functionality. A Memento object holds a snapshot of the object’s state. The Originator creates mementos and restores its state from them, while a Caretaker is responsible for storing mementos but cannot modify them.
This Kotlin implementation uses data classes for conciseness and immutability – a key Kotlin idiom. The Originator’s state is encapsulated within its properties. The Memento holds a copy of this state. The Caretaker simply stores Memento objects in a list. This approach adheres to Kotlin’s preference for immutable data and functional-style programming where applicable, making it clean and easy to understand.
data class Memento(val state: String)
class Originator(var state: String) {
fun createMemento(): Memento {
return Memento(state)
}
fun restoreMemento(memento: Memento) {
state = memento.state
}
}
class Caretaker {
private val mementos = mutableListOf<Memento>()
fun addMemento(memento: Memento) {
mementos.add(memento)
}
fun getMemento(index: Int): Memento? {
return mementos.getOrNull(index)
}
}
fun main() {
val originator = Originator("Initial State")
val caretaker = Caretaker()
caretaker.addMemento(originator.createMemento())
originator.state = "First State"
caretaker.addMemento(originator.createMemento())
originator.state = "Second State"
println("Current State: ${originator.state}")
val previousState = caretaker.getMemento(0)
originator.restoreMemento(previousState!!)
println("Restored State: ${originator.state}")
val latestState = caretaker.getMemento(1)
originator.restoreMemento(latestState!!)
println("Restored State: ${originator.state}")
}
The Memento pattern captures and externalizes the internal state of an object without violating encapsulation. This allows restoring an object to a previous state. Here, a Gist struct holds the text content, and the GistMemento stores a snapshot of that content at a specific time. The Gist provides a method to create a memento, and GistMemento only allows access to its state by the original Gist object. This protects the state integrity. The implementation is idiomatic Rust as it leverages ownership, borrowing, and structs to naturally enforce the required access control and immutability where appropriate.
// Memento Interface
trait Memento {
fn get_state(&self) -> String;
}
// Originator
struct Gist {
content: String,
}
impl Gist {
fn new(initial_content: String) -> Self {
Gist { content: initial_content }
}
fn get_content(&self) -> &String {
&self.content
}
fn set_content(&mut self, new_content: String) {
self.content = new_content;
}
// Creates a memento containing the current state.
fn create_memento(&self) -> GistMemento {
GistMemento { state: self.content.clone() }
}
// Restores the state from a memento. Only the originator can do this.
fn restore_from_memento(&mut self, memento: &GistMemento) {
self.content = memento.get_state().clone();
}
}
// Memento Implementation
struct GistMemento {
state: String,
}
impl GistMemento {
fn get_state(&self) -> String {
self.state.clone()
}
}
// Caretaker (Optional - manages mementos)
struct GistHistory {
mementos: Vec<GistMemento>,
}
impl GistHistory {
fn new() -> Self {
GistHistory { mementos: Vec::new() }
}
fn add_memento(&mut self, memento: GistMemento) {
self.mementos.push(memento);
}
fn get_latest_memento(&self) -> Option<&GistMemento> {
self.mementos.last()
}
}
fn main() {
let mut gist = Gist::new("Initial content.".to_string());
let mut history = GistHistory::new();
println!("Initial content: {}", gist.get_content());
gist.set_content("First edit.".to_string());
history.add_memento(gist.create_memento());
println!("First edit: {}", gist.get_content());
gist.set_content("Second edit.".to_string());
history.add_memento(gist.create_memento());
println!("Second edit: {}", gist.get_content());
// Rollback to the first edit
if let Some(memento) = history.get_latest_memento() {
gist.restore_from_memento(memento);
println!("Rolled back to: {}", gist.get_content());
}
}
The Memento pattern captures and externalizes an object’s internal state so that the object can be restored to this state later, even by another object. It’s particularly useful for implementing undo/redo functionality or saving game states. Our Go implementation defines an Originator holding the state, a Memento representing a snapshot of that state, and a Caretaker responsible for storing and retrieving Mementos without directly accessing the originator’s state. Go’s struct composition and the lack of explicit getters/setters encourage direct state access within the originator, aligning cleanly with the pattern’s intention of encapsulating state within the memento.
package main
import "fmt"
// Memento
type Memento struct {
State string
}
// Originator
type Originator struct {
State string
}
func (o *Originator) CreateMemento() *Memento {
return &Memento{State: o.State}
}
func (o *Originator) Restore(m *Memento) {
o.State = m.State
}
func (o *Originator) String() string {
return fmt.Sprintf("Originator State: %s", o.State)
}
// Caretaker
type Caretaker struct {
Mementos []*Memento
}
func (c *Caretaker) AddMemento(m *Memento) {
c.Mementos = append(c.Mementos, m)
}
func (c *Caretaker) GetMemento(index int) *Memento {
if index < 0 || index >= len(c.Mementos) {
return nil
}
return c.Mementos[index]
}
func main() {
originator := &Originator{State: "State 1"}
caretaker := &Caretaker{}
caretaker.AddMemento(originator.CreateMemento())
originator.State = "State 2"
caretaker.AddMemento(originator.CreateMemento())
originator.State = "State 3"
fmt.Println(originator)
memento := caretaker.GetMemento(0)
if memento != nil {
originator.Restore(memento)
fmt.Println(originator)
}
}
The Memento pattern is a behavioral pattern that allows saving and restoring the internal state of an object without violating encapsulation. It involves three actors: the Originator (holding the state), the Memento (a snapshot of the state), and the Caretaker (responsible for storing and retrieving Mementos). This implementation uses structs to represent the Originator and Memento, and functions to create and restore the state. C’s lack of built-in object orientation necessitates a more procedural approach, but the core concept of encapsulating and preserving state remains. The use of typedef enhances readability.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Originator
typedef struct {
char *state;
} TextEditor;
// Memento
typedef struct {
char *state;
} TextEditorMemento;
// Caretaker
typedef struct {
TextEditorMemento *mementos;
int size;
int capacity;
} TextEditorHistory;
// Function to create a new TextEditor
TextEditor *create_text_editor() {
TextEditor *editor = (TextEditor *)malloc(sizeof(TextEditor));
editor->state = (char *)malloc(100 * sizeof(char));
strcpy(editor->state, "");
return editor;
}
// Function to set the state of the TextEditor
void set_state(TextEditor *editor, const char *state) {
strcpy(editor->state, state);
}
// Function to get the state of the TextEditor
char *get_state(TextEditor *editor) {
return editor->state;
}
// Function to create a Memento
TextEditorMemento *create_memento(const char *state) {
TextEditorMemento *memento = (TextEditorMemento *)malloc(sizeof(TextEditorMemento));
memento->state = (char *)malloc(strlen(state) + 1);
strcpy(memento->state, state);
return memento;
}
// Function to create a TextEditorHistory
TextEditorHistory *create_history(int capacity) {
TextEditorHistory *history = (TextEditorHistory *)malloc(sizeof(TextEditorHistory));
history->mementos = (TextEditorMemento *)malloc(capacity * sizeof(TextEditorMemento));
history->size = 0;
history->capacity = capacity;
return history;
}
// Function to add a Memento to the history
void add_memento(TextEditorHistory *history, TextEditorMemento *memento) {
if (history->size < history->capacity) {
history->mementos[history->size++] = *memento;
}
}
// Function to get the last Memento from the history
TextEditorMemento *get_last_memento(TextEditorHistory *history) {
if (history->size > 0) {
return &history->mementos[history->size - 1];
}
return NULL;
}
// Function to restore the TextEditor from a Memento
void restore_from_memento(TextEditor *editor, TextEditorMemento *memento) {
strcpy(editor->state, memento->state);
}
// Function to free memory
void free_editor(TextEditor *editor) {
free(editor->state);
free(editor);
}
void free_memento(TextEditorMemento *memento) {
free(memento->state);
free(memento);
}
void free_history(TextEditorHistory *history) {
free(history->mementos);
free(history);
}
int main() {
TextEditor *editor = create_text_editor();
TextEditorHistory *history = create_history(5);
set_state(editor, "Hello");
add_memento(history, create_memento(get_state(editor)));
set_state(editor, "World");
add_memento(history, create_memento(get_state(editor)));
printf("Current State: %s\n", get_state(editor));
TextEditorMemento *last_memento = get_last_memento(history);
if (last_memento) {
restore_from_memento(editor, last_memento);
printf("Restored State: %s\n", get_state(editor));
}
free_editor(editor);
free_history(history);
return 0;
}
The Memento pattern is a behavioral design pattern that allows you to capture and externalize the internal state of an object without violating encapsulation. It’s useful for implementing undo/redo functionality, or for saving points in a game. The Originator holds the state, the Memento is an immutable snapshot of that state, and the Caretaker is responsible for storing and retrieving Mementos.
This C++ implementation utilizes private inner classes for Memento to strictly enforce encapsulation. The Editor acts as the originator, holding the text and providing methods to set and get it, alongside creating and restoring from mementos. The History class represents the caretaker, managing a list of EditorMemento objects. Using std::unique_ptr for managing the mementos ensures proper memory management. This conforms to modern C++ practices, emphasizing encapsulation, resource management, and clear separation of concerns.
#include <iostream>
#include <vector>
#include <memory>
class Editor; // Forward declaration
class EditorMemento {
private:
std::string state;
public:
EditorMemento(const std::string& state_) : state(state_) {}
std::string getState() const { return state; }
};
class Editor {
private:
std::string text;
public:
Editor() : text("") {}
void setText(const std::string& text_) {
text = text_;
}
std::string getText() const {
return text;
}
std::unique_ptr<EditorMemento> save() {
return std::make_unique<EditorMemento>(text);
}
void restore(const std::unique_ptr<EditorMemento>& memento) {
text = memento->getState();
}
};
class History {
private:
std::vector<std::unique_ptr<EditorMemento>> mementos;
public:
void push(std::unique_ptr<EditorMemento> memento) {
mementos.push_back(std::move(memento));
}
std::unique_ptr<EditorMemento> pop() {
if (!mementos.empty()) {
auto memento = std::move(mementos.back());
mementos.pop_back();
return memento;
}
return nullptr;
}
};
int main() {
Editor editor;
History history;
editor.setText("Initial text.");
history.push(editor.save());
editor.setText("Text after some changes.");
history.push(editor.save());
editor.setText("Another set of changes!");
history.push(editor.save());
std::cout << "Current state: " << editor.getText() << std::endl;
auto memento = history.pop();
if (memento) {
editor.restore(memento);
std::cout << "Restored to: " << editor.getText() << std::endl;
}
memento = history.pop();
if (memento) {
editor.restore(memento);
std::cout << "Restored to: " << editor.getText() << std::endl;
}
return 0;
}
The Memento pattern is a behavioral design pattern that allows you to capture and externalize the internal state of an object without violating encapsulation. This enables restoring the object to its previous state later. It involves three key players: the Originator (holding the state), the Memento (a snapshot of the state), and the Caretaker (responsible for storing and retrieving Mementos).
Here, GumballMachine is the originator, holding the state (number of gumballs). GumballMachineMemento is a private inner class holding a snapshot of this state. GumballMachineManager is the caretaker, storing and retrieving mementos, providing undo/redo functionality. This implementation utilizes a simple class structure, common in C#, and leverages immutability (the Memento is read-only) to preserve the originator’s state safely. This approach aligns with C#’s encapsulation principles and provides a clear separation of concerns.
// Caretaker
public class GumballMachineManager
{
private GumballMachineMemento memento;
public void Save(GumballMachine gumballMachine)
{
memento = gumballMachine.CreateMemento();
}
public void Restore(GumballMachine gumballMachine)
{
gumballMachine.Restore(memento);
}
}
// Originator
public class GumballMachine
{
private int _gumballs;
public GumballMachine(int gumballs)
{
_gumballs = gumballs;
}
public int Gumballs
{
get { return _gumballs; }
}
public void Dispense(int amount)
{
if (_gumballs >= amount)
{
_gumballs -= amount;
Console.WriteLine($"Dispensing {amount} gumballs. Remaining: {_gumballs}");
}
else
{
Console.WriteLine("Not enough gumballs.");
}
}
// Memento Creation
public GumballMachineMemento CreateMemento()
{
return new GumballMachineMemento(_gumballs);
}
// Memento Restoration
public void Restore(GumballMachineMemento memento)
{
_gumballs = memento.GetGumballs();
Console.WriteLine($"Restored to {_gumballs} gumballs.");
}
// Private Memento class (holds state)
private class GumballMachineMemento
{
private readonly int _gumballs;
private GumballMachineMemento(int gumballs)
{
_gumballs = gumballs;
}
public int GetGumballs()
{
return _gumballs;
}
}
}
// Example Usage
public class Example
{
public static void Main(string[] args)
{
GumballMachine gumballMachine = new GumballMachine(10);
GumballMachineManager mementoManager = new GumballMachineManager();
mementoManager.Save(gumballMachine);
gumballMachine.Dispense(5);
mementoManager.Save(gumballMachine);
gumballMachine.Dispense(2);
mementoManager.Restore(gumballMachine); // Restore to 5 gumballs
mementoManager.Restore(gumballMachine); // Restore to 10 gumballs
}
}
The Memento pattern is a behavioral pattern that allows you to capture and externalize the internal state of an object without violating encapsulation. This is useful for implementing undo/redo functionality, or for restoring an object to a previous state. The pattern consists of three parts: the Originator, which holds the state; the Memento, which is an immutable snapshot of the state; and the Caretaker, which stores and retrieves Mementos.
This TypeScript implementation demonstrates the pattern with a simple TextEditor as the Originator. The TextEditor’s state (the text) is encapsulated within its save() method, which creates a TextEditorMemento holding the current text. The Caretaker, represented by a History, simply stores and retrieves these Mementos. TypeScript’s immutability features (using readonly) and class structures naturally align with the Memento pattern’s principles of encapsulation and state preservation.
// Memento Pattern in TypeScript
// Memento - holds a snapshot of the Originator's state
class TextEditorMemento {
readonly text: string;
constructor(text: string) {
this.text = text;
}
}
// Originator - object whose state is to be saved
class TextEditor {
private text: string;
constructor() {
this.text = "";
}
setText(text: string): void {
this.text = text;
}
getText(): string {
return this.text;
}
// Create a memento to save the current state
save(): TextEditorMemento {
return new TextEditorMemento(this.text);
}
// Restore the state from a memento
restore(memento: TextEditorMemento): void {
this.text = memento.text;
}
}
// Caretaker - stores and retrieves Mementos
class History {
private mementos: TextEditorMemento[] = [];
push(memento: TextEditorMemento): void {
this.mementos.push(memento);
}
pop(): TextEditorMemento | undefined {
return this.mementos.pop();
}
}
// Example Usage
const editor = new TextEditor();
const history = new History();
editor.setText("Initial text.");
history.push(editor.save());
editor.setText("Added more text.");
history.push(editor.save());
editor.setText("Something else...");
console.log("Current Text:", editor.getText());
const lastMemento = history.pop();
if (lastMemento) {
editor.restore(lastMemento);
console.log("Restored Text:", editor.getText());
}
The Memento pattern is a behavioral pattern that allows you to capture and externalize the internal state of an object without violating encapsulation. This enables restoring the object to its previous state later, providing a way to implement undo/redo functionality or checkpointing.
The code defines a TextEditor class representing the object whose state needs to be saved. A History class acts as the Memento holder (caretaker). TextEditor creates TextEditorState objects (Mementos) representing its state. The History stores these states, and the TextEditor can retrieve them to restore previous versions. This uses simple JavaScript objects and class syntax which is a common modern approach, avoiding unnecessary complexity for such a focused pattern.
// Memento (TextEditorState)
class TextEditorState {
constructor(text) {
this.text = text;
this.timestamp = Date.now();
}
}
// Originator (TextEditor)
class TextEditor {
constructor() {
this.text = "";
}
setText(text) {
this.text = text;
}
getState() {
return new TextEditorState(this.text);
}
restore(state) {
this.text = state.text;
}
getText() {
return this.text;
}
}
// Caretaker (History)
class History {
constructor() {
this.states = [];
}
push(state) {
this.states.push(state);
}
pop() {
if (this.states.length > 0) {
return this.states.pop();
}
return null;
}
}
// Example Usage
const editor = new TextEditor();
const history = new History();
editor.setText("Hello");
history.push(editor.getState());
editor.setText("World");
history.push(editor.getState());
editor.setText("!");
console.log(editor.getText()); // Outputs: !
const lastState = history.pop();
editor.restore(lastState);
console.log(editor.getText()); // Outputs: World
const firstState = history.pop();
editor.restore(firstState);
console.log(editor.getText()); // Outputs: Hello
The Memento pattern captures and externalizes an object’s internal state so that the object can be restored to this state later, even if the object is modified or destroyed. This is particularly useful for implementing undo/redo functionality. Here, we use a Memento class to hold the state, an Originator to create and manage the memento, and a Caretaker to store and retrieve mementoes without directly accessing the originator’s state. This implementation is Pythonic due to its reliance on simple classes and data structures, avoiding complex state management within the originator itself.
class Memento:
"""
Holds the state of the Originator.
"""
def __init__(self, state):
self.state = state
def get_state(self):
return self.state
class Originator:
"""
Creates mementos and restores itself from them.
"""
def __init__(self, default_state):
self.state = default_state
def set_state(self, state):
self.state = state
def create_memento(self):
"""
Saves the current state to a Memento.
"""
return Memento(self.state)
def restore_memento(self, memento):
"""
Restores the state from a Memento.
"""
self.state = memento.get_state()
def __str__(self):
return f"State: {self.state}"
class Caretaker:
"""
Stores and retrieves mementos. Doesn't inspect the memento's contents.
"""
def __init__(self):
self.mementos = []
def add_memento(self, memento):
self.mementos.append(memento)
def get_memento(self, index):
return self.mementos[index]
if __name__ == "__main__":
originator = Originator("Initial State")
caretaker = Caretaker()
# Save the initial state
caretaker.add_memento(originator.create_memento())
originator.set_state("First State")
print(originator)
caretaker.add_memento(originator.create_memento())
originator.set_state("Second State")
print(originator)
caretaker.add_memento(originator.create_memento())
# Restore to the first state
originator.restore_memento(caretaker.get_memento(1))
print(originator)
# Restore to the initial state
originator.restore_memento(caretaker.get_memento(0))
print(originator)
The Memento pattern captures and externalizes an object’s internal state so that the object can be restored to this state later, even if the object is modified or moved to another place. It’s useful for implementing undo/redo functionality or for saving game states.
This Java implementation defines a Memento class to hold the state. The Originator encapsulates the state and creates mementos. The Caretaker is responsible for holding mementos but doesn’t operate on the originator’s state; it only provides storage. This separation maintains encapsulation. The inner class Memento provides limited access to its state (only the Originator can access it directly), adhering to encapsulation principles. This design is common in Java, leveraging the power of classes to represent both the state and the logic.
// Memento pattern in Java
// Memento class
class Originator {
private String state;
public Originator(String initialState) {
this.state = initialState;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
// Create a memento to store the current state
public Memento save() {
return new Memento(this.state);
}
// Restore the state from a memento
public void restore(Memento memento) {
this.state = memento.getState();
}
// Inner class Memento
class Memento {
private final String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
}
// Caretaker class
class Caretaker {
private Originator.Memento memento;
public void saveMemento(Originator originator) {
this.memento = originator.save();
}
public void restoreMemento(Originator originator) {
originator.restore(this.memento);
}
}
// Example Usage
public class Main {
public static void main(String[] args) {
Originator originator = new Originator("Initial State");
Caretaker caretaker = new Caretaker();
System.out.println("Initial State: " + originator.getState());
caretaker.saveMemento(originator);
originator.setState("New State");
System.out.println("New State: " + originator.getState());
caretaker.restoreMemento(originator);
System.out.println("Restored State: " + originator.getState());
}
}