Patron Décorateur
Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy. Leçon 77 sur 91.
Le Decorator Pattern est un patron de conception structurel qui vous permet d’ajouter dynamiquement de nouveaux comportements aux objets en les enveloppant dans des objets enveloppes spéciaux appelés décorateurs. Contrairement à l’héritage, qui ajoute un comportement au moment de la compilation, les décorateurs ajoutent un comportement au moment de l’exécution.
Imagine un café. Vous commencez avec un café de base, puis vous ajoutez des extras comme du lait, du sucre ou de la crème fouettée.
Chaque ajout enveloppe le café original et enrichit sa description et son coût. L’idée essentielle est que le café de base et les décorateurs partagent la même interface.
<?php
interface Coffee {
public function getDescription(): string;
public function getCost(): float;
}
class SimpleCoffee implements Coffee {
public function getDescription(): string {
return "Simple Coffee";
}
public function getCost(): float {
return 2.00;
}
}
Les décorateurs implémentent la même interface et enveloppent un autre objet Coffee :
<?php
class MilkDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Milk";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.50;
}
}
class SugarDecorator implements Coffee {
public function __construct(private Coffee $coffee) {}
public function getDescription(): string {
return $this->coffee->getDescription() . ", Sugar";
}
public function getCost(): float {
return $this->coffee->getCost() + 0.25;
}
}
$coffee = new SimpleCoffee();
$coffee = new MilkDecorator($coffee);
$coffee = new SugarDecorator($coffee);
echo $coffee->getDescription() . " = $" . $coffee->getCost();
Sortie :
Simple Coffee, Milk, Sugar = $2.75Chaque décorateur enveloppe l’objet précédent, formant une chaîne. Le modèle vous permet de combiner les comportements dans n’importe quel ordre et en n’importe quelle quantité sans créer une classe pour chaque combinaison possible. Besoin d’une double dose de lait ? Enveloppez-le simplement deux fois.
Défi
FacileConstruisons un système de commande de pizzas à l'aide du patron Decorator. Tu commenceras avec une pizza de base et ajouteras dynamiquement des garnitures : chaque garniture enveloppe la pizza et ajoute des informations à sa description et à son prix, comme dans l'exemple du café de la leçon.
Tu organiseras ton code sur quatre fichiers :
Pizza.php: définis une interfacePizzaqui établit le contrat pour toutes les pizzas et garnitures. Elle doit comporter deux méthodes :getDescription(): stringetgetPrice(): float.BasePizza.php: inclus l'interface Pizza et crée une classeMargheritaPizzaqui l'implémente. Il s'agit de ta pizza de base, avec une description"Margherita"et un prix de8.00.Toppings.php: inclus l'interface Pizza et crée trois classes décoratrices qui l'implémentent. Chaque décorateur enveloppe un objetPizza(reçu dans le constructeur) et enrichit à la fois la description et le prix :CheeseTopping: ajoute", Extra Cheese"à la description et1.50au prixPepperoniTopping: ajoute", Pepperoni"à la description et2.00au prixMushroomTopping: ajoute", Mushrooms"à la description et1.25au prix
main.php: inclus les fichiers BasePizza et Toppings. Tu recevras une entrée : une liste de garnitures séparées par des virgules à ajouter (par exemple,"cheese,pepperoni"ou"mushroom,cheese,cheese").Commence avec une
MargheritaPizza. Pour chaque garniture de l'entrée, enveloppe ta pizza avec le décorateur approprié :"cheese"enveloppe avecCheeseTopping"pepperoni"enveloppe avecPepperoniTopping"mushroom"enveloppe avecMushroomTopping
Après avoir appliqué toutes les garnitures, affiche la description et le prix finaux de la pizza dans ce format :
[description] = $[price]Formate le prix avec deux décimales.
Remarque qu'une même garniture peut être appliquée plusieurs fois : commander une double portion de fromage signifie simplement envelopper la pizza deux fois avec CheeseTopping. C'est toute la puissance du patron Decorator !
Essayez vous-même
<?php
require_once 'BasePizza.php';
require_once 'Toppings.php';
// Lire l'entrée - liste de garnitures séparées par des virgules
$input = trim(fgets(STDIN));
$toppings = explode(',', $input);
// Commencer avec une base MargheritaPizza
$pizza = new MargheritaPizza();
// TODO: Parcourir chaque garniture et envelopper la pizza avec le décorateur approprié
// - "cheese" -> envelopper avec CheeseTopping
// - "pepperoni" -> envelopper avec PepperoniTopping
// - "mushroom" -> envelopper avec MushroomTopping
// TODO: Afficher le résultat au format : [description] = $[price]
// Formater le prix à 2 décimales en utilisant number_format()
?>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