El patrón de recuerdo es un patrón de diseño de software que brinda la capacidad de restaurar un objeto a su estado anterior ( deshacer mediante reversión).
El patrón de recuerdo se implementa con tres objetos: el creador , un cuidador y un recuerdo . El originador es algún objeto que tiene un estado interno. El cuidador va a hacer algo con el creador, pero quiere poder deshacer el cambio. El cuidador primero le pide al creador un objeto de recuerdo. Luego realiza cualquier operación (o secuencia de operaciones) que iba a hacer. Para volver al estado anterior a las operaciones, devuelve el objeto de recuerdo al creador. El objeto de recuerdo en sí es un objeto opaco(uno que el cuidador no puede, o no debe, cambiar). Al usar este patrón, se debe tener cuidado si el creador puede cambiar otros objetos o recursos; el patrón de recuerdo opera en un solo objeto.
Los ejemplos clásicos del patrón de recuerdo incluyen la semilla de un generador de números pseudoaleatorios (siempre producirá la misma secuencia a partir de entonces cuando se inicialice con el estado semilla ) [ cita requerida ] [ aclaración necesaria ] y el estado en una máquina de estados finitos .
Descripción general
El patrón de diseño Memento [1] es uno de los veintitrés patrones de diseño GoF bien conocidos que describen cómo resolver problemas de diseño recurrentes para diseñar software orientado a objetos flexible y reutilizable, es decir, objetos que son más fáciles de implementar, cambiar, probar y reutilizar. El patrón Memento fue creado por Noah Thompson, David Espiritu y el Dr. Drew Clinkenbeard para los primeros productos de HP.
¿Qué problemas puede resolver el patrón de diseño Memento?
- El estado interno de un objeto debe guardarse externamente para que el objeto pueda restaurarse a este estado más adelante.
- No se debe violar la encapsulación del objeto.
El problema es que un objeto bien diseñado está encapsulado de modo que su representación (estructura de datos) está oculta dentro del objeto y no se puede acceder desde fuera del objeto.
¿Qué solución describe el patrón de diseño Memento?
Hacer que un objeto (originador) sea responsable de
- guardar su estado interno en un objeto (recuerdo) y
- restaurar a un estado anterior desde un objeto (recuerdo).
Solo el creador que creó un recuerdo puede acceder a él.
Un cliente (cuidador) puede solicitar un recuerdo del originador (para guardar el estado interno del originador) y pasar un recuerdo al originador (para restaurarlo a un estado anterior).
Esto permite guardar y restaurar el estado interno de un originador sin violar su encapsulación.
Consulte también el diagrama de secuencia y clase UML a continuación.
Estructura
Diagrama de secuencia y clase UML
En el diagrama de clases de UML anterior , la Caretaker
clase se refiere a la Originator
clase para guardar ( createMemento()
) y restaurar ( restore(memento)
) el estado interno del creador.
La Originator
clase implementa
(1) createMemento()
creando y devolviendo un Memento
objeto que almacena el estado interno actual del originador y
(2) restore(memento)
restaurando el estado del Memento
objeto pasado .
El diagrama de secuencia de UML muestra las interacciones en tiempo de ejecución:
(1) Guardar el estado interno del originador: el Caretaker
objeto llama createMemento()
al Originator
objeto, que crea un Memento
objeto, guarda su estado interno actual ( setState()
) y devuelve Memento
al Caretaker
.
(2) Restauración del estado interno del originador: las Caretaker
llamadas restore(memento)
al Originator
objeto y especifica el Memento
objeto que almacena el estado que debe restaurarse. El Originator
Obtiene el estado ( getState()
) desde el Memento
que establecer su propio estado.
Ejemplo de Java
El siguiente programa Java ilustra el uso de "deshacer" del patrón de recuerdo.
import java.util.List ; import java.util.ArrayList ; class Originator { estado de cadena privada ; // La clase también podría contener datos adicionales que no forman parte del // estado guardado en el recuerdo .. conjunto vacío público ( estado de cadena ) { esto . estado = estado ; Sistema . fuera . println ( "Originador: Establecer estado en" + estado ); } public Memento saveToMemento () { System . fuera . println ( "Originador: Guardando en Memento." ); devolver nuevo Memento ( este . estado ); } public void restoreFromMemento ( Memento memento ) { this . estado = recuerdo . getSavedState (); Sistema . fuera . println ( "Originador: Estado después de restaurar desde Memento:" + estado ); } Memento de clase estática pública { estado de cadena final privado ; Memento público ( String stateToSave ) { state = stateToSave ; } // accesible solo por clase externa private String getSavedState () { estado de retorno ; } } } class Caretaker { public static void main ( String [] args ) { List < Originator . Memento > SavedStates = new ArrayList < Originator . Recuerdo > (); Originador originador = nuevo originador (); originador . set ( "Estado1" ); originador . set ( "Estado2" ); SavedStates . agregar ( originador . saveToMemento ()); originador . set ( "Estado3" ); // Podemos solicitar varios recuerdos y elegir a cuál revertir. SavedStates . agregar ( originador . saveToMemento ()); originador . set ( "Estado4" ); originador . restoreFromMemento ( SavedStates . get ( 1 )); } }
La salida es:
Originador: Establecer estado en State1Originador: Establecer estado en State2Creador: Guardar en Memento.Originador: Establecer estado en State3Creador: Guardar en Memento.Originador: Establecer estado en State4Originador: Estado después de restaurar desde Memento: Estado3
Este ejemplo usa una cadena como estado, que es un objeto inmutable en Java. En escenarios de la vida real, el estado casi siempre será un objeto, en cuyo caso se debe hacer una copia del estado.
Hay que decir que la implementación mostrada tiene un inconveniente: declara una clase interna. Sería mejor si esta estrategia de recuerdo pudiera aplicarse a más de un creador.
Hay principalmente otras tres formas de lograr Memento:
- Publicación por entregas.
- Una clase declarada en el mismo paquete.
- También se puede acceder al objeto a través de un proxy, que puede realizar cualquier operación de guardar / restaurar en el objeto.
Ejemplo de C #
El patrón de recuerdo permite capturar el estado interno de un objeto sin violar la encapsulación, de modo que luego se pueden deshacer / revertir los cambios si es necesario. Aquí se puede ver que el objeto de recuerdo se utiliza en realidad para revertir los cambios realizados en el objeto.
class Memento { private readonly string SavedState ; Recuerdo privado ( string stateToSave ) { SavedState = stateToSave ; } originador de clase pública { estado de cadena privada ; // La clase también podría contener datos adicionales que no forman parte del // estado guardado en el recuerdo. public void Set ( estado de la cadena ) { Console . WriteLine ( "Originador: Establecer estado en" + estado ); esto . estado = estado ; } public Memento SaveToMemento () { Console . WriteLine ( "Originador: Guardar en Memento." ); devolver nuevo Memento ( estado ); } public void RestoreFromMemento ( Memento memento ) { estado = memento . SavedState ; Consola . WriteLine ( "Originador: Estado después de restaurar desde Memento:" + estado ); } } }class Caretaker { static void Main ( string [] args ) { List < Memento > SavedStates = new List < Memento > (); Memento . Originador originador = nuevo Memento . Originador (); originador . Establecer ( "Estado1" ); originador . Establecer ( "Estado2" ); SavedStates . Agregar ( originador . SaveToMemento ()); originador . Establecer ( "Estado3" ); // Podemos solicitar varios recuerdos y elegir a cuál revertir. SavedStates . Agregar ( originador . SaveToMemento ()); originador . Establecer ( "Estado4" ); originador . RestoreFromMemento ( SavedStates [ 1 ]); } }
Ejemplo de Python
"" " Ejemplo de patrón de recuerdo. " ""class Memento : def __init__ ( self , state ) -> None : self . _state = estado def get_saved_state ( self ): devuelve self . _Expresar originador de la clase : _state = "" def set ( self , state ) -> None : print ( "Originador: Estableciendo estado en" , state ) self . _state = estado def save_to_memento ( self ) -> Memento : print ( "Originator: Saving to Memento." ) return Memento ( self . _state ) def restore_from_memento ( self , memento ) -> Ninguno : self . _state = recuerdo . get_saved_state () print ( "Originador: Estado después de restaurar desde Memento:" , self . _state )Saved_states = [] originator = Originator () originador . set ( "State1" ) originador . set ( "State2" ) Saved_states . añadir ( originador . save_to_memento ())originador . set ( "State3" ) Saved_states . añadir ( originador . save_to_memento ())originador . set ( "Estado4" )originador . restore_from_memento ( Saved_states [ 1 ])
Referencias
- ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Patrones de diseño: elementos de software orientado a objetos reutilizable . Addison Wesley. págs. 283 y siguientes . ISBN 0-201-63361-2.CS1 maint: varios nombres: lista de autores ( enlace )
- ^ "El patrón de diseño de Memento - Problema, solución y aplicabilidad" . w3sDesign.com . Consultado el 12 de agosto de 2017 .
- ^ "El patrón de diseño Memento - Estructura y colaboración" . w3sDesign.com . Consultado el 12 de agosto de 2017 .
enlaces externos
- Descripción del patrón Memento en Ada
- Diagrama de clases Memento UML con ejemplos de código C # y .NET
- Tutorial de creación de fuentes
- Patrón de diseño Memento usando Java