El patrón Memento captura y almacena el estado actual de un objeto, para poder restaurarlo a ese estado, sin exponer los detalles internos de su implementación (encapsulamiento).
Hace un snapshot del objeto sin exponer su estado interno.
Ataca varios problemas:
Restauración de Estado: Permite guardar y restaurar el estado de un objeto a un estado anterior sin exponer su implementación interna.
Violación del Encapsulamiento: Evita que el estado interno del objeto sea expuesto o modificado directamente, manteniendo el encapsulamiento.
Permite que un objeto (el “originador”) guarde su estado interno en un objeto memento y lo recupere más tarde.
Este patrón es recomendable cuando:
Cumplimiento del Encapsulamiento: Mantiene el encapsulamiento completo del objeto de origen.
Simplicidad para el Origen: Simplifica el objeto de origen, ya que delega el manejo de estados a otro objeto.
Historial de Estados: Permite mantener un historial de estados del objeto.
Uso de Memoria: Almacenar mementos puede requerir una cantidad importante de memoria, sobre todo si los estados son grandes o se guardan con frecuencia.
Complejidad: Se necesitan clases adicionales para los mementos y su manejo.
Potencial de Objetos Obsoletos: Si el objeto de origen cambia significativamente, los mementos antiguos pueden volverse incompatibles o irrelevantes.
Debemos crear un editor de texto que permite a los usuarios crear y editar documentos.
Una característica crucial es la capacidad de deshacer y rehacer sus cambios. Esta funcionalidad mejora el uso y brinda seguridad, permitiendo hacer cambios sin temor a cometer errores permanentes.
El desafío principal es implementar la funcionalidad de “deshacer” de manera eficiente y sin exponer o comprometer la estructura interna del objeto que representa el documento de texto.
Los usuarios deben poder deshacer una serie de cambios en el texto a un estado anterior específico, sin afectar la integridad del editor.
La implementación directa de esta funcionalidad puede llevar a un diseño complicado y propenso a errores.
Elegimos el patrón Memento, porque nos permite guardar y restaurar el estado anterior de un objeto (en este caso, el contenido del Editor de Texto) sin revelar los detalles de su implementación.
El patrón Memento brinda una forma de capturar y almacenar el estado interno de un objeto a través de snapshots en un momento determinado, y luego restaurar el objeto a esos estados anteriores, todo ello manteniendo la encapsulación.
Creamos el TextMemento, que va a mantener el estado. La clase TextEditor, el originador, vamos a querer mantener el estado de este objeto. El Caretaker, que va a mantener una pila de Memento, para poder deshacer los estados. Finalmente el cliente, que configura y usa el Memento.
Codificamos en Java lo que preparamos en el diagrama.
Creamos la clase Memento:
class TextMemento {
private final String state;
public TextMemento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
Implementamos el Originator:
class TextEditor {
private String content;
public void setText(String text) {
content = text;
}
public String getText() {
return content;
}
public TextMemento save() {
return new TextMemento(content);
}
public void restore(TextMemento memento) {
content = memento.getState();
}
}
Definimos la interfaz CareTaker:
class Caretaker {
private final Stack mementos = new Stack<>();
public void saveMemento(TextMemento memento) {
mementos.push(memento);
}
public TextMemento getMemento() {
if (!mementos.empty()) {
return mementos.pop();
}
return null;
}
}
El código cliente:
public class EditorApp {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
Caretaker caretaker = new Caretaker();
editor.setText(“Hello”);
caretaker.saveMemento(editor.save());
editor.setText(“Hello, World!”);
caretaker.saveMemento(editor.save());
// Deshacer al estado anterior
editor.restore(caretaker.getMemento());
System.out.println(editor.getText()); // Debería imprimir “Hello”
// Deshacer otro estado
editor.restore(caretaker.getMemento());
System.out.println(editor.getText()); // Debería imprimir el texto inicial o estar vacío
}
}
Los participantes que vimos antes son: Memento, Originator, CareTaker, Client:
En este ejemplo vimos cómo EditorApp (Cliente) interactúa con TextEditor (Originator) y Caretaker para guardar y restaurar estados del texto usando TextMemento (Memento).
Nos permitió tomar snpashots del estado del objeto y restaurarlo, de manera sencilla.
Se puede usar con Memento para implementar acciones reversibles, como “deshacer“.
Se puede usar para recorrer una colección de Mementos.