Patrones de diseño - Memento

El patrón Memoria (Memento) se utiliza para guardar y restaurar el estado de un objeto. Este patrón se engloba dentro de los patrones de comportamiento.

Necesidad

En muchas ocasiones podemos tener la necesidad de guardar el estado de un objeto para poder volver a ese punto en algún momento. Puede ser durante la realización de un proceso largo y complejo, como la realización de algún cálculo científico o el autosalvado de fase de algunos videojuegos,  en los que queremos ir guardando el estado conforme vamos realizando cambios para tener un punto de retorno seguro.

Con este fin tenemos el patrón memento que se implementa usando 3 participantes:

  • Memento: Que se encarga de guardar el estado interno del objeto originator
  • Originator: Objeto que salva su estado interno, crea un memento que contiene un snapshot de su estado interno y puede usarlo para restaurar su estado
  • Caretaker: Registra y guarda los diferentes estados salvados, los mementos

Implementación

Vamos a implementar un sistema de snapshot de estado para un proceso. El sistema implementado en la clase ProcessOriginator (que actúa de originator) va guardando estados en diferentes momentos usando la clase Memento. Estos estados son almacenados en una lista en la clase EstadosProcess (que representa a la clase caretaker) que se puede usar para restaurar cualquiera de los estados.

La representación de las clases sería así:

Patrón Memento

Código en Vala

Tenemos primero la clase ProcesosOriginator que es la clase que tienen la capacidad de guardar los estados. La clase tiene unos atributos y los métodos guardarMemento que instancia una nueva clase memento con los datos actuales y restaurarMemento que restaura el estado con los datos del memento que le pasamos como parámetro:

ProcesoOriginator.vala
class ProcesosOriginator : GLib.Object 
{ 
    public string nombre { get; set; default="--"; } 
    public string procesos { get; set; default="--"; } 
    public int cantidad { get; set; default=0; } 
     
    public Memento guardarMemento () 
    { 
        print ("Guardando el estado...\n"); 
        return new Memento (_nombre, _procesos, _cantidad); 
    } 
     
    public void restaurarMemento ( Memento memento ) 
    { 
        print ("Restaurando el estado...\n"); 
        _nombre = memento.nombre; 
        _procesos = memento.procesos; 
        _cantidad = memento.cantidad; 
    } 
     
    public void verProceso() 
    { 
        print ("----------\n"); 
        print (@"Nombre: $(_nombre)\n"); 
        print (@"Procesos: $(_procesos)\n"); 
        print (@"Cantidad: $(_cantidad)\n"); 
        print ("----------\n"); 
    } 
} 

La clase Memento es muy sencilla, contiene los datos de ProcesosOriginator que se le pasan en el constructor: 

Memento.vala
class Memento : GLib.Object 
{ 
    public string nombre { get; private set; default="--"; } 
    public string procesos { get; private set; default="--"; } 
    public int cantidad { get; private set; default=0; } 
     
    public Memento (string nombre, string procesos, int cantidad) 
    { 
        _nombre = nombre; 
        _procesos = procesos; 
        _cantidad = cantidad; 
    }  
} 

El caretaker que nos falta en nuestro patrón Memento lo tenemos en la clase EstadosProcesos que mantiene un ArrayList<Memento> en el que se van añadiendo los estados que vamos tomando en la clase Memento y nos permite restaurar el estado que queramos:

EstadosProcesos.vala
using Gee;  
 
class EstadosProcesos : GLib.Object 
{ 
    private ArrayList<Memento> mementos = new ArrayList<Memento>(); 
     
    public void addEstado (Memento memento)  
    { 
        mementos.add (memento); 
    } 
     
    public Memento getEstado (int index) 
    { 
        return mementos.get (index); 
    } 
     
    public void verEstados () 
    { 
        print ("Estados guardados:\n"); 
        foreach (var memento in mementos) {  
            print ("\t%s:%s:%d\n", memento.nombre, 
                                memento.procesos, 
                                memento.cantidad);  
        }  
    } 
} 

El cliente lo tenemos en la clase UsoPatronMemento que instancia una clase EstadosProcesos para ir guardando los estados, y una clase ProcesosOriginator que vamos cambiando, mostrando y salvando su contenido. Luego mostramos todos los estados salvados y restauramos el estado 0:

UsoPatronMemento.vala
class UsoPatronMemento : GLib.Object 
{ 
    public static int main (string[] args) 
    { 
        Intl.setlocale (ALL); 
         
        EstadosProcesos estado = new EstadosProcesos(); 
        ProcesosOriginator proceso = new ProcesosOriginator(); 
        proceso.nombre = "proceso-A"; 
        proceso.procesos = "cargando sistema"; 
        proceso.cantidad = 20; 
         
        proceso.verProceso(); 
        // Guardamos el primer estado 
        estado.addEstado ( proceso.guardarMemento() ); 
         
        proceso.nombre = "proceso-B"; 
        proceso.procesos = "cargando controladores"; 
        proceso.cantidad = 40; 
         
        proceso.verProceso(); 
        // Guardamos un segundo estado 
        estado.addEstado ( proceso.guardarMemento() );  
         
        proceso.nombre = "proceso-C"; 
        proceso.procesos = "ajustando variables"; 
        proceso.cantidad = 80; 
         
        proceso.verProceso(); 
        // Guardamos un tercer estado 
        estado.addEstado ( proceso.guardarMemento() );  
         
        // Listamos los estados guardados 
        estado.verEstados ();  
         
        // Restauramos al estado 0 
        proceso.restaurarMemento ( estado.getEstado (0) ); 
         
        proceso.verProceso(); 
         
        return 0; 
    } 
} 

Construimos y ejecutamos el programa:

❯ valac --pkg=gee-0.8 Memento.vala EstadosProcesos.vala ProcesosOriginator.vala UsoPatronMemento.vala -o UsoPatronMemento
❯ ./UsoPatronMemento
----------
Nombre: proceso-A
Procesos: cargando sistema
Cantidad: 20
----------
Guardando el estado...
----------
Nombre: proceso-B
Procesos: cargando controladores
Cantidad: 40
----------
Guardando el estado...
----------
Nombre: proceso-C
Procesos: ajustando variables
Cantidad: 80
----------
Guardando el estado...
Estados guardados:
    proceso-A:cargando sistema:20
    proceso-B:cargando controladores:40
    proceso-C:ajustando variables:80
Restaurando el estado...
----------
Nombre: proceso-A
Procesos: cargando sistema
Cantidad: 20
----------

 

Indice de Patrones

(1 Voto)
Etiquetado como :

Deja un comentario

Asegúrese de introducir toda la información requerida, indicada por un asterisco (*). No se permite código HTML.