informaticaPC

Patrones de Diseño Software

Memento

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.

Memento en UML

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:

Ejemplo

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:

Ejemplo

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.
Primera página Anterior Siguiente Última página
Usamos cookies para ofrecerte una experiencia mejorada, el continuar navegando supone que aceptas su uso