Le design pattern State
Description
Le design pattern State permet à un objet d’adapter son comportement en fonction de son état interne.
Exemple
Nous nous intéressons aux commandes de produits sur notre site de vente en ligne. Elles sont décrites par la classe Commande. Les instances de cette classe possèdent un cycle de vie qui est illustré par le diagramme d’états-transitions de la figure 25.1. L’état EnCours est l’état où la commande est en cours de constitution : le client ajoute des produits. L’état Validée est l’état où la commande a été validée et réglée par le client. Enfin, l’état Livrée est l’état où les produits ont été livrés.
Figure 25.1 - Diagramme d’états-transitions d’une commande
La classe Commande possède des méthodes dont le comportement diffère en fonction de cet état. Par exemple, la méthode ajouteProduit n’ajoute des produits que si la commande se trouve dans l’état EnCours. De même, la méthode efface n’a pas de comportement dans les états Livrée et Validée.
L’approche traditionnelle pour résoudre ces différences de comportement consiste à utiliser des branchements conditionnels dans le corps des méthodes. Cette approche conduit souvent à des méthodes complexes à écrire et à maintenir, noyées...
Structure
1. Diagramme de classes
La figure 25.3 illustre la structure générique du design pattern State.
Figure 25.3 - Structure du design pattern State
2. Participants
Les participants au design pattern State sont les suivants :
-
MachineEtat (Commande) est une classe concrète décrivant des objets qui sont des machines à états, c’est-à-dire qui possèdent un ensemble d’états pouvant être décrit par un diagramme d’états-transitions. Cette classe détient une référence vers une instance d’une sous-classe d’Etat qui définit l’état courant.
-
Etat (AbstractEtatCommande) est une classe abstraite qui introduit la signature des méthodes liées à l’état et qui gère l’association avec la machine à états.
-
EtatConcretAet EtatConcretB (CommandeEnCours, CommandeValidee et CommandeLivree) sont des sous-classes concrètes qui implémentent le comportement des méthodes relativement à chaque état.
3. Collaborations
La machine à états délègue les appels des méthodes dépendant de l’état courant vers un objet d’état.
La machine à états peut transmettre à l’objet d’état une référence vers elle-même si c’est nécessaire....
Domaines d’application
Le design pattern State est utilisé dans les cas suivants :
-
Le comportement d’un objet dépend de son état.
-
L’implémentation de cette dépendance à l’état par des branchements conditionnels s’avère trop complexe.
Exemple en PHP
Nous présentons l’exemple de la figure 25.2 en PHP. La classe Commande est décrite à la suite. Les méthodes ajouteProduit, retireProduit et efface dépendent de l’état. Par conséquent leur implémentation consiste à appeler la méthode correspondante de l’instance référencée par etatCommande.
Le constructeur de la classe initialise l’attribut etatCommande avec une instance de la classe CommandeEnCours. La méthode etatSuivant passe à l’état suivant en associant une nouvelle instance à l’attribut etatCommande.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\State;
class Commande
{
protected array $produits = [];
protected AbstractEtatCommande $etatCommande;
public function __construct()
{
$this->etatCommande = new CommandeEnCours($this);
}
public function getProduits(): array
{
return $this->produits;
}
public function effaceProduits(): void
{
$this->produits = [];
}
public function rajoute(Produit $produit): void
{
$this->produits[] = $produit;
}
public function ajouteProduit(Produit $produit): void
{
$this->etatCommande->ajouteProduit($produit);
}
public function retireProduit(Produit $produit): void
{
$this->etatCommande->retireProduit($produit);
}
public function efface(): void
{
$this->etatCommande->efface();
}
public...