El patrón Memento se encarga de capturar y externalizar el estado interno de un objeto para que este pueda ser restaurado más adelante sin exponer los detalles internos del objeto. Es especialmente útil en situaciones donde es necesario realizar un seguimiento del estado de un objeto en diferentes momentos del tiempo.
1. Encapsulación de Estados: Permite guardar el estado de un objeto sin violar su encapsulación.
2. Deshacer y Rehacer: Facilita la implementación de funcionalidades de deshacer y rehacer en aplicaciones.
3. Simplicidad en el Manejo de Estados: Simplifica la gestión de estados complejos en objetos.
El patrón Memento se compone de tres elementos clave:
1. Originador: El objeto que tiene un estado interno y puede crear un Memento de su estado actual y restaurarlo a partir del mismo.
2. Memento: El objeto que almacena el estado interno del Originador.
3. Cuidador (Caretaker): El encargado de almacenar y restaurar los Mementos sin modificar su contenido.
El Originador es la clase cuyos estados queremos salvar y restaurar. Esta clase contiene una función para crear un Memento y otra para restaurar su estado desde un Memento.
public class Originador {
private String estado;
public void setEstado(String estado) {
this.estado = estado;
}
public String getEstado() {
return estado;
}
public Memento guardarEstadoEnMemento() {
return new Memento(estado);
}
public void obtenerEstadoDeMemento(Memento memento) {
estado = memento.getEstado();
}
public static class Memento {
private final String estado;
public Memento(String estado) {
this.estado = estado;
}
private String getEstado() {
return estado;
}
}
}
El Memento es una clase anidada estática dentro del Originador que almacena el estado. Esta clase es privada para proteger el estado del Originador.
El Cuidador es responsable de guardar los Mementos. Esta clase no modifica ni examina el contenido de los Mementos.
import java.util.ArrayList;
import java.util.List;
public class Cuidador {
private List<Originador.Memento> mementoList = new ArrayList<>();
public void addMemento(Originador.Memento memento) {
mementoList.add(memento);
}
public Originador.Memento getMemento(int index) {
return mementoList.get(index);
}
}
Vamos a implementar el patrón Memento paso a paso para entender mejor cómo funcionan los componentes juntos.
El Originador es la clase que queremos proteger y gestionar su estado.
public class Originador {
private String estado;
public void setEstado(String estado) {
this.estado = estado;
}
public String getEstado() {
return estado;
}
public Memento guardarEstadoEnMemento() {
return new Memento(estado);
}
public void obtenerEstadoDeMemento(Memento memento) {
estado = memento.getEstado();
}
public static class Memento {
private final String estado;
public Memento(String estado) {
this.estado = estado;
}
private String getEstado() {
return estado;
}
}
}
La clase Memento es anidada dentro del Originador y no expone su estado directamente.
El Cuidador almacena los Mementos sin conocer su contenido.
import java.util.ArrayList;
import java.util.List;
public class Cuidador {
private List<Originador.Memento> mementoList = new ArrayList<>();
public void addMemento(Originador.Memento memento) {
mementoList.add(memento);
}
public Originador.Memento getMemento(int index) {
return mementoList.get(index);
}
}
Finalmente, integramos estas clases para ver cómo funcionan juntas.
public class MementoPatternDemo {
public static void main(String[] args) {
Originador originador = new Originador();
Cuidador cuidador = new Cuidador();
originador.setEstado("Estado #1");
originador.setEstado("Estado #2");
cuidador.addMemento(originador.guardarEstadoEnMemento());
originador.setEstado("Estado #3");
cuidador.addMemento(originador.guardarEstadoEnMemento());
originador.setEstado("Estado #4");
System.out.println("Estado actual: " + originador.getEstado());
originador.obtenerEstadoDeMemento(cuidador.getMemento(0));
System.out.println("Primer estado guardado: " + originador.getEstado());
originador.obtenerEstadoDeMemento(cuidador.getMemento(1));
System.out.println("Segundo estado guardado: " + originador.getEstado());
}
}
El patrón Memento es ideal en situaciones donde es necesario mantener un historial de estados. Algunos ejemplos incluyen:
Implementar funcionalidades de deshacer y rehacer
en editores de texto, aplicaciones de dibujo, y similares.
Manejo de estados complejos en juegos, simulaciones y aplicaciones financieras.
El patrón Memento es ideal para implementar funcionalidades de deshacer y rehacer, y para manejar estados de objetos complejos.
El principal inconveniente es el uso de memoria adicional para almacenar múltiples estados.
El impacto en el rendimiento depende de la frecuencia y el tamaño de los estados almacenados.
Sí, el patrón Memento se puede combinar con otros patrones de diseño como el Comando y el Estado para crear soluciones más robustas.
El patrón de diseño Memento es una herramienta poderosa para gestionar estados de objetos en Java, ofreciendo una solución elegante para implementar funcionalidades de deshacer y rehacer. Su correcta implementación puede mejorar significativamente la robustez y la mantenibilidad del código.
Jorge García
Fullstack developer