Patrones de diseño de comportamiento: Memento

Intención del patrón

Sin violar el encapsulamiento, captura y externaliza el estado interno de un objeto para que el objeto pueda ser devuelto a dicho estado posteriormente.
Una cookie mágica que encapsula un "punto de control".
Proporciona la capacidad de deshacer el estado completo de un objeto.

Ejemplo de problema

Se necesita restaurar un objeto a su estado previo (por ejemplo: operaciones del tipo "deshacer" o "rollback").


Discusión

Un cliente solicita un Memento de un objeto cuando se necesita un punto de control del estado de dicho objeto. El objeto inicializa al Memento con una caracterización de su estado. El cliente es el "guardián" del Memento, pero sólo el objeto original puede almacenar y recuperar información del Memento (el Memento es "opaco" para el cliente y todos los demás objetos. Si el cliente más adelante necesita realizar un rollback sobre el estado del objeto origen, devuelve el Memento al objeto origen para que éste restaure su estado.
Una capacidad ilimitada de "deshacer" y "rehacer" puede ser fácilmente implementada con una pila de objetos Command y una pila de objetos Memento.

El patrón de diseño Memento define tres roles diferentes:
  1. Originador: Es el objeto que sabe cómo resguardarse a sí mismo.
  2. Guardián: Es el objeto que conoce por qué y cuándo el Originador necesita almacenar y restaurarse a sí mismo.
  3. Memento: La "caja" de almacenamiento que es utilizado como almacenamiento por el Originador y cuidado por el Guardián.

Estructura


Ejemplo

El patrón de diseño Memento captura y exterioriza el estado interno de un objeto para que el mismo pueda ser restaurado a dicho estado. Este patrón es común entre los mecanismos de reparación "hágalo usted mismo" de frenos de tambor de autos. Los tambores son removidos de ambos lados, exponiendo ambos frenos, el derecho y el izquierdo. Sólo un lado es desarmado y el otro sirve como un Memento de cómo las partes del freno encajan juntas. Sólo después de haber finalizado el trabajo en un lado, se puede desarmar el otro. Cuando el segundo lado es desarmado, el primero actúa de Memento.

Check list


  1. Identificar los roles de "guardián" y "Originador".
  2. Crear una clase Memento y declarar al Originador como friend.
  3. El guardián conoce cuando almacenar un "punto de control" del originador.
  4. El originador crea un Memento y copia su estado a dicho Memento.
  5. El guardián conserva al Memento pero sin conocer su contenido.
  6. El guardián sabe cuando debe volver al originador a su estado anterior.
  7. El originador se restablece a sí mismo utilizando el estado almacenado en el Memento.


Reglas de oro

Command y Memento actúan como tokens mágicos que son pasados e invocados posteriormente. En Command, el token representa una solicitud; en Memento representa el estado interno de un objeto en un momento determinado. El polimorfismo es importante para Command, pero no para Memento, porque su interfaz es tan reducida que sólo puede ser pasado como valor.
Command puede usar a Memento para mantener un estado requerido para implementar una operación deshacer/rollback.
Memento es usado a menudo en conjunto con Iterator. Un objeto de tipo Iterator puede usar a un Memento para capturar el estado de una iteración. El Iterator almacena el Memento internamente.

Ejemplo de código en #

using System;

namespace DoFactory.GangOfFour.Memento.Structural
{
  // MainApp startup class for Structural 
  // Memento Design Pattern.
  class MainApp
  {
     // Entry point into console application.
    static void Main()
    {
      Originator o = new Originator();
      o.State = "On";

      // Store internal state
      Caretaker c = new Caretaker();
      c.Memento = o.CreateMemento();

      // Continue changing originator
      o.State = "Off";

      // Restore saved state
      o.SetMemento(c.Memento);

      // Wait for user
      Console.ReadKey();
    }
  }

  // The 'Originator' class
  class Originator
  {
    private string _state;

    // Property
    public string State
    {
      get { return _state; }
      set
      {
        _state = value;
        Console.WriteLine("State = " + _state);
      }
    }

    // Creates memento 
    public Memento CreateMemento()
    {
      return (new Memento(_state));
    }

    // Restores original state
    public void SetMemento(Memento memento)
    {
      Console.WriteLine("Restoring state...");
      State = memento.State;
    }
  }

  // The 'Memento' class
  class Memento
  {
    private string _state;

    // Constructor
    public Memento(string state) {
      this._state = state;
    }

    // Gets or sets state
    public string State
    {
      get { return _state; }
    }
  }

  // The 'Caretaker' class
  class Caretaker
  {
    private Memento _memento;

    // Gets or sets memento
    public Memento Memento
    {
      set { _memento = value; }
      get { return _memento; }
    }
  }
}

2 comentarios:

Anónimo dijo...

Muy interesante, gracias

Juan Barrionuevo dijo...

Me alegra que te haya parecido interesante.

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

 
Copyright 2009 Programación SOLIDa
BloggerTheme by BloggerThemes | Design by 9thsphere