El patrón de diseño Command
Descripción
El patrón de diseño Command tiene como objetivo transformar una solicitud en un objeto, facilitando operaciones tales como la anulación, la puesta en fila de espera de las solicitudes y su seguimiento.
Ejemplo
En ciertos casos, la gestión de una solicitud puede ser bastante compleja: puede ser anulada, puesta en fila de espera o trazada. En el marco de nuestro sistema de venta de vehículos, el gestor puede solicitar al catálogo rebajar el precio de los vehículos de ocasión que llevan en stock cierto tiempo. Por motivos de simplicidad, esta solicitud debe poderse anular y, eventualmente, restablecer.
Para gestionar esta anulación, una primera solución consiste en indicar a nivel de cada vehículo si está o no rebajado. Esta solución no es suficiente, pues un mismo vehículo puede estar rebajado varias veces con tasas diferentes. Otra solución sería conservar su precio antes de la última rebaja, aunque esta solución no es satisfactoria pues la anulación puede realizarse sobre otra solicitud de rebaja que no sea la última.
El patrón de diseño Command responde a este problema transformando la solicitud en un objeto cuyos atributos van a contener los parámetros así como el conjunto de objetos sobre los que la solicitud va a ser aplicada. En nuestro ejemplo, esto haría posible anular o restablecer una solicitud de rebaja.
La figura 19.1 ilustra esta aplicación del patrón de diseño Command a nuestro ejemplo. La clase SolicitudRebaja almacena sus tres parámetros...
Estructura
1. Diagrama de clases
La figura 19.3 detalla la estructura genérica del patrón de diseño Command.
Figura 19.3 - Estructura del patrón de diseño Command
2. Participantes
Los participantes del patrón de diseño Command son los siguientes:
-
Solicitud (SolicitudInterfaz) es la interfaz que presenta la firma del método ejecuta (rebaja) que ejecuta la solicitud.
-
SolicitudConcreta (SolicitudRebaja) implementa el método ejecuta (rebaja), gestiona la asociación con el o los receptores e implementa el método anula, que almacena el estado (o los valores necesarios) para poder anular a continuación.
-
Cliente (nuestro código cliente) crea e inicializa la solicitud y la transmite al solicitante.
-
Solicitante (Catalogo) almacena y ejecuta la solicitud (método ejecutaSolicitudRebaja) así como eventualmente las solicitudes de anulación.
-
Receptor (Vehiculo) ejecuta las acciones necesarias para realizar la solicitud o para anularla.
3. Colaboraciones
La figura 19.4 ilustra las colaboraciones del patrón de diseño Command:
-
El cliente crea una solicitud concreta especificando el o los receptores.
-
El cliente transmite esta solicitud al método ejecutaSolicitudRebaja del solicitante que empieza por almacenar la solicitud.
-
El solicitante ejecuta a continuación la solicitud llamando al método ejecuta.
-
El estado o los datos necesarios para realizar...
Dominios de aplicación
El patrón de diseño Command se utiliza en los casos siguientes:
-
Un objeto debe configurarse para realizar un procesamiento concreto. En el caso del patrón de diseño Command, es el solicitante el que se configura mediante una solicitud que contiene la descripción de un procesamiento a realizar en uno o varios receptores.
-
Las solicitudes deben apilarse y poder ejecutarse en un momento cualquiera, eventualmente varias veces.
-
Las solicitudes deben poder anularse.
-
Las solicitudes deben poder registrarse en un archivo de log.
-
Las solicitudes deben poder agruparse en forma de transacción. Una transacción es un conjunto ordenado de solicitudes que actúan sobre el estado de un sistema y que pueden ser anuladas.
Ejemplo en PHP
Presentamos a continuación un ejemplo escrito en PHP. La clase Vehiculo se describe en PHP como aparece a continuación. Cada vehículo posee un nombre, una fecha de entrada en el almacén y un precio de venta. El método modificaPrecio permite ajustar el precio mediante un coeficiente.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Command;
class Vehiculo
{
protected string $nombre;
protected int $fechaEntradaStock;
protected float $precioVenta;
public function __construct(string $nombre, int
$fechaEntradaStock, float $precioVenta)
{
$this->nombre = $nombre;
$this->fechaEntradaStock = $fechaEntradaStock;
$this->precioVenta = $precioVenta;
}
public function getDuracionAlmacenamiento(int $hoy): int
{
return $hoy - $this->fechaEntradaStock;
}
public function modificarPrecio(float $coeficiente): void
{
$this->precioVenta = round($coeficiente *
$this->precioVenta, 2);
}
public function muestra(): void
{
$precio = number_format($this->precioVenta, 2, ',', ' ');
echo "$this->nombre precio: $precio - fecha de entrada stock
$this->fechaEntradaStock" . PHP_EOL;
}
}
La clase ListaVehiculo gestiona una lista de vehículos con una sencilla matriz. Su código es el siguiente.
Esta clase solo se usa para simplificar la implementación, lo que explica su ausencia en el diagrama UML de las clases de la figura 19.1.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Command;
class ListaVehiculo
{
protected array...