Le design pattern Command
Description
Le design pattern Command a pour objectif de transformer une requête en un objet, facilitant des opérations comme l’annulation, la mise en file d’attente des requêtes et leur suivi.
Exemple
Dans certains cas, la gestion d’une commande peut être assez complexe : elle peut être annulée, mise en attente ou être tracée. Dans le cadre de notre système de vente de véhicules, le gestionnaire peut demander au catalogue de solder les véhicules d’occasion présents dans le stock depuis une certaine durée. Pour des raisons de facilité, cette demande doit pouvoir être annulée puis, éventuellement, rétablie.
Pour gérer cette annulation, une première solution consiste à indiquer au niveau de chaque véhicule s’il est ou non soldé. Cette solution n’est pas suffisante car un même véhicule peut être soldé plusieurs fois avec des taux différents. Une autre solution serait alors de conserver son prix avant la dernière remise, mais cette solution n’est pas non plus satisfaisante car l’annulation peut porter sur une autre requête de remise que la dernière.
Le design pattern Command répond à ce problème en transformant la requête en un objet dont les attributs vont contenir les paramètres ainsi que l’ensemble des objets sur lesquels la requête a été appliquée. Dans notre exemple, il deviendrait ainsi possible d’annuler ou de rétablir une requête...
Structure
1. Diagramme de classes
La figure 19.3 détaille la structure générique du design pattern Command.
Figure 19.3 - Structure du design pattern Command
2. Participants
Les participants au design pattern Command sont les suivants :
-
Commande (CommandeInterface) est l’interface qui introduit la signature de la méthode lance (solde) qui exécute la commande.
-
CommandeConcrete (CommandeSolder) implémente la méthode lance (solde), gère l’association avec le ou les récepteurs et implémente la méthode annule, qui stocke l’état (ou les valeurs nécessaires) pour pouvoir annuler par la suite.
-
Client (notre code client) crée et initialise la commande puis la transmet à l’appelant.
-
Appelant (Catalogue) stocke et lance la commande (méthode lanceCommandeSolder) ainsi qu’éventuellement les requêtes d’annulation.
-
Recepteur (Vehicule) traite les actions nécessaires pour effectuer la commande ou pour l’annuler.
3. Collaborations
La figure 19.4 illustre les collaborations du design pattern Command :
-
Le client crée une commande concrète en spécifiant le ou les récepteurs.
-
Le client transmet cette commande à la méthode lanceCommandeSolder de l’appelant qui commence par stocker la commande.
-
L’appelant exécute ensuite la commande en invoquant la méthode...
Domaines d’application
Le design pattern Command est utilisé dans les cas suivants :
-
Un objet doit être paramétré par un traitement à réaliser. Dans le cas du design pattern Command, c’est l’appelant qui est paramétré par une commande qui contient la description d’un traitement à réaliser sur un ou plusieurs récepteurs.
-
Les commandes doivent être empilées et pouvoir être exécutées à un moment quelconque, éventuellement plusieurs fois.
-
Les commandes doivent pouvoir être annulées.
-
Les commandes doivent pouvoir être tracées dans un fichier de log.
-
Les commandes doivent pouvoir être regroupées sous la forme d’une transaction. Une transaction est un ensemble ordonné de commandes qui agissent sur l’état d’un système et qui peuvent être annulées.
Exemple en PHP
Nous présentons maintenant l’exemple en PHP. La classe Vehicule s’écrit en PHP comme suit. Chaque véhicule possède un nom, une date d’entrée dans le stock et un prix de vente. La méthode modifiePrix permet d’ajuster le prix avec un coefficient.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Command;
class Vehicule
{
protected string $nom;
protected int $dateEntreeStock;
protected float $prixVente;
public function __construct(string $nom, int $dateEntreeStock,
float $prixVente)
{
$this->nom = $nom;
$this->dateEntreeStock = $dateEntreeStock;
$this->prixVente = $prixVente;
}
public function getDureeStockage(int $aujourdhui): int
{
return $aujourdhui - $this->dateEntreeStock;
}
public function modifiePrix(float $coefficient): void
{
$this->prixVente = round($coefficient * $this->prixVente,
2);
}
public function affiche(): void
{
$prix = number_format($this->prixVente, 2, ',', ' ');
echo "$this->nom prix: $prix - entrée en stock le
$this->dateEntreeStock" . PHP_EOL;
}
}
La classe ListeVehicule gère une liste de véhicules à l’aide d’un simple tableau. Son code est décrit à la suite.
Cette classe n’est utile que pour simplifier l’implémentation, ce qui explique son absence du diagramme UML des classes de la figure 19.1.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Command;
class ListeVehicule
{
protected array $vehicules = [];
public function getVehicules(): array
{
return $this->vehicules;
} ...