El patrón de diseño Memento es uno de los patrones de comportamiento que permite guardar y restaurar el estado de un objeto sin violar el principio de encapsulamiento. Este patrón es útil cuando necesitamos poder deshacer o rehacer operaciones, manteniendo un registro de los estados anteriores de un objeto.
En este artículo, veremos qué es el patrón Memento, sus componentes principales y cómo implementarlo en PHP con un ejemplo práctico.
El patrón Memento se utiliza para capturar el estado interno de un objeto sin exponer sus detalles internos, y luego restaurar ese estado cuando sea necesario. Esto permite volver a un estado anterior del objeto, lo que es ideal para implementar funcionalidades de "deshacer" (undo) o "rehacer" (redo).
El patrón Memento se compone de tres partes clave:
1. Originador (Originator): El objeto cuyo estado se quiere salvar y restaurar.
2. Memento: El contenedor que almacena el estado del Originador
.
3. Cuidador (Caretaker): Gestiona los Mementos, almacenando y restaurando los estados del Originador
.
Memento
.
Originador
.
A continuación, implementaremos el patrón Memento en PHP mediante un ejemplo práctico en el que simulamos un editor de texto que puede deshacer los cambios.
Memento
La clase Memento
será responsable de almacenar el estado del objeto. En este caso, simplemente guardará el texto de un editor.
<?php
class Memento {
private $state;
public function __construct(string $state) {
$this->state = $state;
}
public function getState(): string {
return $this->state;
}
}
Originator
La clase Originator
es el objeto que queremos guardar y restaurar. En este ejemplo, será un editor de texto con una propiedad $text
. Esta clase puede crear un memento que guarde su estado actual y restaurar su estado desde un memento dado.
<?php
class TextEditor {
private $text;
public function __construct() {
$this->text = "";
}
public function write(string $words) {
$this->text .= $words;
}
public function getText(): string {
return $this->text;
}
// Crear un Memento para guardar el estado actual
public function save(): Memento {
return new Memento($this->text);
}
// Restaurar el estado desde un Memento
public function restore(Memento $memento) {
$this->text = $memento->getState();
}
}
Caretaker
El Caretaker
será el responsable de manejar los mementos. Esta clase almacenará los diferentes estados del editor de texto, permitiendo deshacer cambios.
<?php
class Caretaker {
private $history = [];
public function saveMemento(Memento $memento) {
$this->history[] = $memento;
}
public function getMemento(int $index): ?Memento {
return $this->history[$index] ?? null;
}
public function getHistory(): array {
return $this->history;
}
}
Ahora que tenemos las clases necesarias (Memento
, TextEditor
, y Caretaker
), podemos ver cómo se utilizan en conjunto para implementar la funcionalidad de deshacer cambios en el editor de texto.
<?php
// Crear el editor de texto y el cuidador
$editor = new TextEditor();
$caretaker = new Caretaker();
// Escribir algo de texto en el editor
$editor->write("Hola, ");
$editor->write("este es un ");
$editor->write("ejemplo del patrón Memento.");
// Guardar el estado actual
$caretaker->saveMemento($editor->save());
echo "Texto actual: " . $editor->getText() . "\n";
// Escribir más texto
$editor->write(" Añadiendo más texto.");
echo "Texto después de agregar más: " . $editor->getText() . "\n";
// Guardar el nuevo estado
$caretaker->saveMemento($editor->save());
// Restaurar al estado anterior (deshacer)
$editor->restore($caretaker->getMemento(0));
echo "Texto después de deshacer: " . $editor->getText() . "\n";
// Restaurar al último estado (rehacer)
$editor->restore($caretaker->getMemento(1));
echo "Texto después de rehacer: " . $editor->getText() . "\n";
1. El TextEditor
empieza vacío, pero escribimos varias líneas de texto usando el método write()
.
2. Guardamos el estado del editor llamando al método save()
del TextEditor
y almacenamos el memento en el Caretaker
mediante saveMemento()
.
3. Escribimos más texto en el editor y volvemos a guardar el estado actual.
4. Para deshacer los cambios, restauramos el primer memento que guardamos y el editor regresa al estado anterior.
5. Para rehacer, restauramos el último memento que guardamos, recuperando el estado más reciente.
El patrón Memento es una solución elegante cuando se necesita guardar y restaurar el estado de un objeto sin comprometer el encapsulamiento. En PHP, este patrón es fácil de implementar y resulta muy útil para funcionalidades como deshacer/rehacer, editores de texto, o cualquier aplicación que requiera guardar el estado de un objeto en un momento dado.
Mediante el uso de las clases Memento
, TextEditor
y Caretaker
, se puede gestionar el historial de cambios de manera eficiente, garantizando que el código sea mantenible y escalable.
Jorge García
Fullstack developer