Este patrón de diseño es útil cuando manejamos un objeto que necesitaremos restaurar a estados anteriores (como por ejemplo cuando utilizamos la función de deshacer en un procesador de textos).
En la imagen de la derecha se muestra su estructura según el libro de GoF mencionado al principio del presente tutorial.
Main.java:
package Memento;
public class Main
{
public static void main(String[] args)
{
// Crear el objeto originador/creador
Originator creador = new Originator("Pedro", "Gil Mena");
// Crear el objeto gestor/vigilante del Memento
Caretaker vigilante= new Caretaker();
// Crear el Memento y asociarlo al objeto gestor
vigilante.setMemento( creador.createMemento() );
// Mostrar los datos del objeto
System.out.println("Nombre completo: [" + creador.getNombre() + " " + creador.getApellidos() + "]" );
// Modificar los datos del objeto
creador.setNombre("María");
creador.setApellidos("Mora Miró");
// Mostrar los datos del objeto
System.out.println("Nombre completo: [" + creador.getNombre() + " " + creador.getApellidos() + "]" );
// Restaurar los datos del objeto
creador.setMemento( vigilante.getMemento() );
// Mostrar los datos del objeto
System.out.println("Nombre completo: [" + creador.getNombre() + " " + creador.getApellidos() + "]" );
}
}
Originator.java (Originador según el diagrama anterior):
package Memento;
public class Originator
{
private String nombre;
private String apellidos;
// ---------------------------
public Originator(String nombre, String apellidos) {
this.nombre = nombre;
this.apellidos = apellidos;
}
// ---------------------------
public void setMemento(Memento m) {
this.nombre = m.getNombre();
this.apellidos = m.getApellidos();
}
// ---------------------------
public Memento createMemento() {
return new Memento(nombre, apellidos);
}
// ---------------------------
public String getNombre() {
return this.nombre;
}
// ---------------------------
public void setNombre(String nombre) {
this.nombre = nombre;
}
// ---------------------------
public String getApellidos() {
return this.apellidos;
}
// ---------------------------
public void setApellidos(String apellidos) {
this.apellidos = apellidos;
}
}
Memento.java:
package Memento;
public class Memento
{
private String nombre;
private String apellidos;
// ---------------------------
public Memento(String nombre, String apellidos) {
this.nombre = nombre;
this.apellidos = apellidos;
}
// ---------------------------
public String getNombre() {
return this.nombre;
}
// ---------------------------
public void setNombre(String nombre) {
this.nombre = nombre;
}
// ---------------------------
public String getApellidos() {
return this.apellidos;
}
// ---------------------------
public void setApellidos(String apellidos) {
this.apellidos = apellidos;
}
}
Caretaker.java (Conserje según el diagrama anterior):
package Memento;
public class Caretaker
{
private Memento memento;
// ---------------------------
public void setMemento(Memento memento) {
this.memento = memento;
}
// ---------------------------
public Memento getMemento() {
return this.memento;
}
}
Con el código anterior obtendríamos como salida:
EXPLICACIÓN:
- Al inicio del programa creamos un objeto de tipo Originator (que deseamos poder restaurar si se producen cambios) y otro de tipo Caretaker que utilizaremos a su vez para gestionar otro de tipo Memento (en el cual quedará registrado el estado anterior del primero de ellos, y que utilizaremos para restaurarlo).
- A continuación se muestran los datos iniciales del objeto de tipo Originator, y tras modificarlos se volverán a restaurar al estado inicial.
Basándonos en este ejemplo, en la clase Caretaker también podríamos haber definido una lista en la que ir guardando una instancia de Memento por cada modificación que se realizase en el objeto de tipo Originator, para de dicho modo implementar la funcionalidad de restaurar los últimos cambios de uno en uno.
Ahora veamos un último ejemplo en que utilizamos este patrón para guardar y recuperar marcadores a las páginas de un libro:
Main.java:
package Memento2;
public class Main
{
public static void main(String[] args)
{
GestorMarcadores objGestorMarcadores = new GestorMarcadores();
// Abrimos el libro y vamos a la página 10
Libro libro = new Libro();
libro.irPagina(10);
// Guardamos la página en marcadores
objGestorMarcadores.addPosicionMarcador( libro.guardarMarcador() );
// Saltamos a la página 83
libro.irPagina(83);
// Guardamos la página en marcadores
objGestorMarcadores.addPosicionMarcador( libro.guardarMarcador() );
// Volvemos a la primera página guardada en marcadores
libro.recuperarPagina( objGestorMarcadores.getPosicionMarcador(0) );
// Saltamos a la segunda página guardada en marcadores
libro.recuperarPagina( objGestorMarcadores.getPosicionMarcador(1) );
}
}
Libro.java (Originator en el diagrama anterior):
package Memento2;
public class Libro
{
private int pagina_actual;
// ------------------------------
public void irPagina( int pagina ) {
this.pagina_actual = pagina;
System.out.println("Agregado marcador en página [" + this.pagina_actual + "]");
}
// ------------------------------
public Memento guardarMarcador() {
System.out.println("Marcador guardado");
return new Memento( this.pagina_actual );
}
// ------------------------------
public void recuperarPagina(Memento m) {
this.pagina_actual = m.getMarcadorPagina();
System.out.println("Volvemos a la página: " + pagina_actual);
}
}
Memento.java:
package Memento2;
public class Memento
{
private int estado;
// ------------------------------
public Memento( int estado ) {
this.estado = estado;
}
// ------------------------------
public void setMarcadorPagina( int estado ) {
this.estado = estado;
}
// ------------------------------
public int getMarcadorPagina() {
return this.estado;
}
}
GestorMarcadores.java (Caretaker en el diagrama anterior):
package Memento2;
import java.util.ArrayList;
public class GestorMarcadores
{
private ArrayList<Memento> marcadores = new ArrayList<Memento>();
// ------------------------------
public void addPosicionMarcador(Memento m) {
marcadores.add(m);
}
// ------------------------------
public Memento getPosicionMarcador(int indice) {
return marcadores.get(indice);
}
}
El código anterior daría como salida:
EXPLICACIÓN:
- Al iniciarse el programa se crea tanto una instancia de la clase Libro como otra de GestorMarcadores, que guardará una lista en la que se almacenarán las referencias a los marcadores.
- Cada marcador es creado utilizando el método guardarMarcador() de un objeto Libro, quedando almacenado el número de página en un objeto de tipo Memento, el cual será posteriormente guardado en una lista mediante el método addPosicionMarcador() de GestorMarcador().
- El uso del método irPagina() es méramente ilustrativo, no siendo necesario para el correcto funcionamiento del ejemplo.