Patron État
Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy. Leçon 79 sur 91.
Le pattern State est un patron de conception comportemental qui permet à un objet de modifier son comportement lorsque son état interne change. Au lieu d’utiliser des conditions complexes pour gérer différents états, vous encapsulez chaque état dans sa propre classe et déléguez le comportement à l’objet d’état actuel.
Imagine un distributeur automatique. Il se comporte différemment selon qu’il attend de l’argent, qu’il a reçu un paiement ou qu’il distribue un produit.
Chaque état possède ses propres règles concernant les actions autorisées. Le modèle State représente cela en créant une classe pour chaque état.
<?php
interface OrderState {
public function proceed(Order $order): string;
public function getStatus(): string;
}
class PendingState implements OrderState {
public function proceed(Order $order): string {
$order->setState(new ProcessingState());
return "Order moved to processing";
}
public function getStatus(): string {
return "Pending";
}
}
class ProcessingState implements OrderState {
public function proceed(Order $order): string {
$order->setState(new ShippedState());
return "Order has been shipped";
}
public function getStatus(): string {
return "Processing";
}
}
class ShippedState implements OrderState {
public function proceed(Order $order): string {
return "Order already shipped";
}
public function getStatus(): string {
return "Shipped";
}
}
La classe de contexte contient une référence vers l’état actuel et lui délègue les appels :
<?php
class Order {
private OrderState $state;
public function __construct() {
$this->state = new PendingState();
}
public function setState(OrderState $state): void {
$this->state = $state;
}
public function proceed(): string {
return $this->state->proceed($this);
}
public function getStatus(): string {
return $this->state->getStatus();
}
}
$order = new Order();
echo $order->getStatus() . "\n";
echo $order->proceed() . "\n";
echo $order->getStatus() . "\n";
echo $order->proceed() . "\n";
echo $order->getStatus();
Sortie :
Pending
Order moved to processing
Processing
Order has been shipped
ShippedLe pattern State élimine les instructions switch tentaculaires et facilite l’ajout de nouveaux états. Chaque classe d’état est chargée de savoir quel est l’état suivant, ce qui permet de garder une logique organisée et facile à maintenir.
Défi
FacileConstruisons un système de workflow de documents en utilisant le modèle State. Les documents d’un système de gestion de contenu passent par différentes étapes : brouillon, révision et publication, chaque étape ayant ses propres règles concernant les actions autorisées et ce qui se produit lorsque vous essayez de faire avancer le document.
Vous organiserez votre code dans quatre fichiers :
DocumentState.php: définissez une interfaceDocumentStatequi établit le contrat pour tous les états de document. Elle doit comporter deux méthodes :publish(Document $document): stringpour tenter de faire avancer le document, etgetStatus(): stringpour renvoyer le nom de l’état actuel.States.php: incluez l’interface DocumentState et créez trois classes d’état qui l’implémentent :DraftState: lorsquepublish()est appelée, elle fait passer le document àReviewStateet renvoie"Document sent for review". Son statut est"Draft".ReviewState: lorsquepublish()est appelée, elle fait passer le document àPublishedStateet renvoie"Document published". Son statut est"Under Review".PublishedState: lorsquepublish()est appelée, elle renvoie"Document is already published"sans modifier l’état. Son statut est"Published".
Document.php: incluez le fichier States et créez une classeDocumentqui joue le rôle de contexte. Votre document doit :- accepter un titre dans son constructeur et commencer dans l’état
DraftState - posséder une méthode
setState(DocumentState $state): voidpour modifier l’état actuel - posséder une méthode
publish(): stringqui délègue à la méthodepublish()de l’état actuel - posséder une méthode
getStatus(): stringqui renvoie le statut de l’état actuel
- accepter un titre dans son constructeur et commencer dans l’état
main.php: incluez le fichier Document. Vous recevrez une entrée : le nombre de fois où appelerpublish()sur le document.Créez un
Documentavec le titre"My Article". Commencez par afficher le statut initial. Ensuite, appelezpublish()le nombre de fois indiqué, en affichant le résultat de chaque appel sur une nouvelle ligne. Enfin, affichez le statut final.Format de sortie :
Status: [initial status] [publish result 1] [publish result 2] ... Status: [final status]
Chaque classe d’état sait quel est l’état suivant dans le workflow, ce qui permet de garder la logique des transitions organisée et facile à modifier. Ajouter un nouvel état tel que "Archived" consisterait simplement à créer une nouvelle classe et à mettre à jour les transitions concernées.
Essayez vous-même
<?php
require_once 'Document.php';
// Lire l'entrée - nombre de fois à appeler publish()
$n = intval(trim(fgets(STDIN)));
// TODO: Créer un Document avec le titre "My Article"
// TODO: Afficher le statut initial au format : "Status: [status]"
// TODO: Appeler publish() n fois, en affichant chaque résultat sur une nouvelle ligne
// TODO: Afficher le statut final au format : "Status: [status]"
?>Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses et objetsLe mot-clé $thisMéthodesPropriétésConstructeur (__construct)Destructeur (__destruct)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLe mot-clé parent::Redéfinition des méthodesLe mot-clé finalClasses abstraitesRécapitulatif – Hiérarchie des employés7Encapsulation
Public, Protected, PrivateModificateurs d’accès en profondeurAccesseurs et mutateursDissimulation de l’informationPromotion des constructeurs (8.0)Récapitulatif – Système de fiches étudiant10Concepts avancés de la POO
Composition ou héritageInjection de dépendancesClasses anonymesÉnumérations (PHP 8.1)Fibres (PHP 8.1)Approfondissement du clonage d’objetsGénérateurs et itérateurs13Patrons de conception – Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode modèlePatron ÉtatPatron CompositePatron Dépôt2Espaces de noms et chargement automatique
Introduction aux espaces de nomsLe mot-clé useNorme de chargement automatique PSR-4Autoloader de ComposerRécapitulatif - Projet organisé5Interfaces et contrats
Introduction aux interfacesImplémentation des interfacesImplémentation de plusieurs interfacesInterface ou classe abstraiteIndication de type avec les interfacesRécapitulatif - Calculateur de formes8Méthodes magiques
Introduction aux méthodes magiques__toString et __debugInfo__get, __set, __isset, __unset__call et __callStatic__clone et clonage d’objets__serialize et __unserializeRécapitulatif - Collection personnalisée3Propriétés de classe
Propriétés d’instance vs statiquesConstantes dans les classesMéthodes et propriétés statiquesPropriétés privées et protégéesPropriétés en lecture seule (PHP 8.1)Récapitulatif - Gestionnaire de comptes bancaires6Polymorphisme
Révision de la redéfinition des méthodesPolymorphisme via les interfacesAnnotations de type et types unionLiaison statique tardiveRécapitulatif - Processeur de paiements9Traits
Introduction aux traitsUtilisation de plusieurs traitsRésolution des conflits entre traitsMéthodes abstraites dans les traitsTraits par rapport à l’héritage12Patrons de conception – Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron StrategyEntraînez-vous par vous-même : Compilateur PHP en ligne