El patrón de diseño Memento
Descripción
El patrón de diseño Memento tiene como objetivo salvaguardar y restablecer el estado de un objeto sin violar la encapsulación.
Ejemplo
Durante la compra online de un vehículo nuevo, el cliente puede seleccionar opciones suplementarias que se agregarán a su carrito de la compra. No obstante, existen opciones incompatibles como, por ejemplo, asientos deportivos frente a asientos en cuero o reclinables.
La consecuencia de esta incompatibilidad es que si se han seleccionado asientos reclinables y a continuación se eligen asientos en cuero, la opción de los asientos reclinables se elimina del carrito de la compra.
Queremos incluir una opción para poder anular la última operación realizada en el vehículo. Suprimir la última opción agregada no es suficiente puesto que es necesario también restablecer las opciones presentes y que se han eliminado debido a la incompatibilidad. Una solución consiste en memorizar el estado del carrito de la compra antes de agregar la nueva opción.
Además, deseamos ampliar este comportamiento para gestionar un histórico de los estados del carrito de la compra y poder volver a cualquier estado anterior. Es preciso entonces, en este caso, memorizar todos los estados sucesivos del vehículo.
Para preservar la encapsulación del objeto que representa el carrito de la compra, una solución consistiría en memorizar estos estados intermedios en el propio carrito. No obstante esta solución tendría como efecto un aumento inútil...
Estructura
1. Diagrama de clases
La figura 23.2 detalla la estructura genérica del patrón de diseño Memento.
Figura 23.2 - Estructura del patrón de diseño Memento
2. Participantes
Los participantes del patrón de diseño Memento son los siguientes:
-
Memento es la clase de los mementos, que son los objetos que memorizan el estado interno de los objetos originales (o una parte de este estado). El memento posee dos interfaces: una interfaz completa destinada a los objetos originales que ofrece la posibilidad de memorizar y restaurar su estado y una interfaz reducida para los objetos de gestión del estado que no tienen permisos para acceder al estado interno de los objetos originales.
-
ObjetoOriginal (CarritoOpciones) es la clase de los objetos que crean un memento para memorizar su estado interno y que pueden restaurarlo a partir de un memento.
-
GestionEstado es el responsable de la gestión de los mementos y no accede al estado interno de los objetos originales.
3. Colaboraciones
Una instancia de GestionEstado solicita un memento al objeto original llamando al método creaMemento, hace una copia de seguridad y, en caso de necesitar su anulación y retornar al estado memorizado en el memento, lo transmite de nuevo al objeto original mediante el método setMemento.
Dominios de aplicación
El patrón de diseño Memento se utiliza en el caso en que el estado interno de un objeto deba memorizarse (total o parcialmente) para poder ser restaurado posteriormente sin que la encapsulación de este objeto deba ser violada.
Ejemplo en PHP
Comenzamos presentando este ejemplo escrito en PHP con el memento. Este está descrito por la interfaz MementoInterfaz y la clase concreta Memento. La clase incluye los métodos getEstado y setEstado cuya invocación está reservada al carrito de la compra.
El memento almacena el estado del carrito de opciones, a saber una lista que está constituida por una réplica de la lista de opciones del carrito.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Memento;
interface MementoInterfaz
{
public function setEstado(ListaOpcionVehiculo $opciones): void;
public function getEstado(): ListaOpcionVehiculo;
}
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Memento;
class Memento implements MementoInterfaz
{
protected ListaOpcionVehiculo $opciones;
public function __construct()
{
$this->opciones = new ListaOpcionVehiculo();
}
public function setEstado(ListaOpcionVehiculo $opciones): void
{
$this->opciones->borra();
$this->opciones->agrega($opciones);
}
public function getEstado(): ListaOpcionVehiculo
{
return $this->opciones;
}
}
La clase Memento usa la clase ListaOpcionVehiculo, cuyo código fuente se ilustra a continuación. Esta clase gestiona una lista de opciones en forma de una matriz.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Memento;
class ListaOpcionVehiculo
{
protected array $opciones...