lunes, 4 de mayo de 2015

Memento

Memento

Propósito

Memento guarda parte o todo el estado interno de un objeto, para que este objeto pueda ser restaurado más tarde al estado guardado por Memento. Esta operación debe ocurrir sin romper el principio del encapsulamiento.

También conocido como: Token

Motivación

Muchas veces es necesario guardar el estado interno de un objeto. Esto debido a que tiempo después, se necesita restaurar el estado del objeto, al que previamente se ha guardado.
Para facilitar el hacer y deshacer de determinadas operaciones, para lo que habrá que guardar los estados anteriores de los objetos sobre los que se opere (o bien recordar los cambios de forma incremental).

Aplicabilidad

El patrón Memento es aplicable cuando:

  • Todo o parte del estado de un objeto debe ser guardado para ser restaurado más tarde.
  • Cuando una interfaz directa para obtener el estado de un objeto exponga detalles de su implementación.
Estructura


Participantes

Memento
  • Almacena el estado interno de un objeto Originator. El Memento puede almacenar mucho o parte del estado interno de Originator.
  • Tiene dos interfaces. Una para Caretaker, que le permite manipular el Memento únicamente para pasarlo a otros objetos. La otra interfaz sirve para que Originator pueda almacenar/restaurar su estado interno, sólo Originator puede acceder a esta interfaz, al menos en teoría.
Originator
  • Crea un objeto Memento conteniendo una fotografía (un instante) de su estado interno.
  • Usa a Memento para restaurar su estado interno.
Caretaker
  • Es responsable por mantener a salvo a Memento.
  • No opera o examina el contenido de Memento.
Colaboraciones
  • Un Carataker solicita un memento a un creador, lo almacena durante un tiempo y se lo devuelve a su creador, tal y como muestra el diagrama.
  • A veces el Carataker no devolverá el memento a su creador, ya que el creador podría no necesitar nunca volver a un estado anterior.
  • Los mementos son pasivos. Sólo el creador que creó el memento asignará o recuperará su estado.

Consecuencias

El patrón Memento tiene las siguientes consecuencias:

  1. Preserva la encapsulación. Originator crea un Memento y el mismo almacena su estado interno, de esta manera no es necesario exponer el estado interno como atributos de acceso público, preservando así la encapsulación.
  2. Simplificar Originator. Memento podría incurrir en gastos considerables si Originator tiene que almacenar y mantener a salvo una o muchas copias de su estado interno, sus responsabilidades crecerían y serían más complejas, se desviaría de su propósito disminuyendo la coherencia. Usar Mementos hace que Originator sea mucho más sencillo y coherente.
  3. Uso frecuente de Mementos para almacenar estados internos de gran tamaño, podría resultar costoso y perjudicar el rendimiento del sistema.
  4. Definiendo interfaces. Esto puede ser difícil en algunos lenguajes ya que sólo originator puede acceder al estado de memento.
  5. Altos costos en mantener momentos. Caretaker al no conocer detalles del estado interno de Originator, no tiene idea de cuánto espacio y tiempo se necesita para almacenar el estado interno de Originator en un Memento y restaurar su estado interno a partir de un Memento. Por lo que no puede hacer predicciones de tiempo ni de espacio.
Implementación

Hay dos cuestione que debemos tener en cuenta al implementar el patrón Memento:

  1. Soporte del lenguaje. Para implementar este patrón, debemos considerar que el Memento debe proporcionar una interfaz accesible sólo por Originator, en la mayoría de los lenguajes de programación, esta figura no es posible, sin embargo en C++ se puede hacer que Originator sea una clase amiga de Memento.
  2. Almacenando cambio incrementales. Cuando mementos son creados y pasan a través del origen (originator) con una secuencia predecible, el Memento puede guardar los cambios incrementalmente en el estado interno del origen.
Código de ejemplo

La salida en pantalla es:

Originator: Setting state to State1 
Originator: Setting state to State2 
Originator: Saving to Memento. 
Originator: Setting state to State3 
Originator: Saving to Memento. 
Originator: Setting state to State4 
Originator: State after restoring from Memento: State3
-------------------------------------------------------------------
import java.util.*;

class Memento
{
    private String state;

    public Memento(String stateToSave)
    {
        state = stateToSave;
    }

    public String getSavedState()
    {
        return state;
    }
}

class Originator
{
    private String state;
    /* lots of memory consumptive private data that is not necessary to define the
     * state and should thus not be saved. Hence the small memento object. */

    public void set(String state)
    {
       System.out.println("Originator: Setting state to "+state);
       this.state = state;
    }

    public Memento saveToMemento()
    {
        System.out.println("Originator: Saving to Memento.");
        return new Memento(state);
    }

    public void restoreFromMemento(Memento m)
    {
        state = m.getSavedState();
        System.out.println("Originator: State after restoring from Memento: "+state);
    }
}  

class Caretaker {
   private ArrayList<Memento> savedStates = new ArrayList<Memento>();

   public void addMemento(Memento m) { savedStates.add(m); }
   public Memento getMemento(int index) { return savedStates.get(index); }
}  

class MementoExample {
   public static void main(String[] args) {
       Caretaker caretaker = new Caretaker();

       Originator originator = new Originator();
       originator.set("State1");
       originator.set("State2");
       caretaker.addMemento( originator.saveToMemento() );
       originator.set("State3");
       caretaker.addMemento( originator.saveToMemento() );
       originator.set("State4");

       originator.restoreFromMemento( caretaker.getMemento(1) );
   }
}
---------------------------------------------------------------
/**
 * Memento pattern: Copy the information into a another class for recovery in the future if necessary
 * @author Pperez
 *
 */

public class MementoPattern {
                public void main(String args[]){
                               RegularClass regularClass = new RegularClass();
                               regularClass.setData("First Report");
                               System.out.println(regularClass.data);
                               regularClass.makeBackup();
                               regularClass.setData("Second Report");
                               System.out.println(regularClass.data);
                               regularClass.recoverBackup();
                               System.out.println(regularClass.data);
                }

                public class Memento{
                               public String memoryData;

                               public Memento(String data){
                                               this.memoryData=data;
                               }

                               public String recoverOldInformation(){
                                               return memoryData;
                               }
                }

                public class RegularClass{
                               Memento memento;
                               String data;
                               public RegularClass(){

                               }
                               public void setData(String data){
                                               this.data = data;
                               }
                               public void makeBackup(){
                                                memento = new Memento(data);
                               }
                               public void recoverBackup(){
                                    data = memento.recoverOldInformation();
                               }
                }
}

Usos conocidos

El Patrón de Diseño Memento se utiliza para situaciones donde se requiera una operación de restauración “UNDO”, como en los graficadores y procesadores de texto.

Patrones relacionados
  • Command: Puede usar “Mementos” para guardar el estado de operaciones restaurables.
  • Iterator: “Mementos” puede ser usado con Iterator para buscar colecciones para estados específicos.
Referencias
  • Design Patterns Elements of Reusable Object-Oriented Software, GoF.
  • http://www.ldc.usb.ve/~mgoncalves/IS2/sd07/grupo3.pdf
  • http://kybele.escet.urjc.es/documentos/SI/Patrones/15_MEMENTO.ppt
  • http://www.freewebz.com/amanecer/personal/papers/paper.memento.pdf  


No hay comentarios:

Publicar un comentario