Patron Strategy
Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy. Leçon 74 sur 91.
Le pattern Strategy est un patron de conception comportemental qui vous permet de définir une famille d’algorithmes, d’encapsuler chacun d’eux dans sa propre classe et de les rendre interchangeables à l’exécution. L’objet qui utilise la stratégie n’a pas besoin de savoir quel algorithme il exécute.
Imaginez un panier d’achat qui peut appliquer différentes stratégies de réduction. Au lieu de coder en dur la logique des réductions avec des conditions, vous définissez chaque réduction comme une classe distincte :
<?php
interface DiscountStrategy {
public function calculate(float $total): float;
}
class NoDiscount implements DiscountStrategy {
public function calculate(float $total): float {
return $total;
}
}
class PercentageDiscount implements DiscountStrategy {
public function __construct(private int $percent) {}
public function calculate(float $total): float {
return $total - ($total * $this->percent / 100);
}
}
class FixedDiscount implements DiscountStrategy {
public function __construct(private float $amount) {}
public function calculate(float $total): float {
return max(0, $total - $this->amount);
}
}
La classe de contexte accepte n’importe quelle stratégie et délègue le calcul :
<?php
class ShoppingCart {
public function __construct(private DiscountStrategy $discount) {}
public function setDiscount(DiscountStrategy $discount): void {
$this->discount = $discount;
}
public function checkout(float $total): float {
return $this->discount->calculate($total);
}
}
$cart = new ShoppingCart(new NoDiscount());
echo $cart->checkout(100) . "\n";
$cart->setDiscount(new PercentageDiscount(20));
echo $cart->checkout(100);
Sortie :
100
80Le pattern Strategy est particulièrement utile lorsque vous disposez de plusieurs façons d’effectuer une opération et que vous souhaitez passer de l’une à l’autre sans modifier la classe qui les utilise. Ajouter un nouveau type de remise signifie créer une nouvelle classe, sans toucher au code existant.
Défi
FacileConstruisons un calculateur de frais d’expédition à l’aide du patron Strategy. Les différentes méthodes d’expédition ont des règles de tarification différentes : l’expédition standard facture un tarif fixe, l’expédition express ajoute un pourcentage et l’expédition de nuit combine les deux. Le patron Strategy vous permet de remplacer ces calculs sans modifier le code qui les utilise.
Vous organiserez votre code sur quatre fichiers :
ShippingStrategy.php: créez une interfaceShippingStrategyqui définit le contrat pour toutes les méthodes d’expédition. Elle doit disposer d’une méthodecalculate(float $weight): floatqui prend le poids du colis et renvoie le coût de l’expédition.ShippingMethods.php: incluez le fichier ShippingStrategy et créez trois classes qui implémentent l’interface :StandardShipping: facture un tarif fixe de$5.00, quel que soit le poidsExpressShipping: facture$2.00par kilogramme (multipliez le poids par 2)OvernightShipping: facture des frais de base de$10.00plus$3.00par kilogramme
ShippingCalculator.php: incluez le fichier ShippingStrategy et créez une classeShippingCalculatorqui joue le rôle de contexte. Votre calculateur doit :- Accepter un
ShippingStrategydans son constructeur (utilisez la promotion du constructeur) - Disposer d’une méthode
setStrategy(ShippingStrategy $strategy): voidpour modifier la méthode d’expédition au moment de l’exécution - Disposer d’une méthode
calculateCost(float $weight): floatqui délègue le calcul à la stratégie actuelle
- Accepter un
main.php: incluez les fichiers ShippingMethods et ShippingCalculator. Vous recevrez deux entrées : un type d’expédition ("standard","express"ou"overnight") et le poids d’un colis.Créez un
ShippingCalculatoren commençant parStandardShipping. En fonction de l’entrée correspondant au type d’expédition, utilisezsetStrategy()pour passer à la méthode d’expédition appropriée. Calculez ensuite le coût pour le poids donné et affichez le résultat avec deux décimales.La sortie doit être :
Shipping cost: $[cost]
Ce défi montre comment le patron Strategy rend votre système d’expédition flexible : l’ajout d’une nouvelle méthode d’expédition comme SameDayShipping nécessite uniquement de créer une nouvelle classe qui implémente l’interface, sans modifier le calculateur ni les méthodes d’expédition existantes.
Essayez vous-même
<?php
require_once 'ShippingMethods.php';
require_once 'ShippingCalculator.php';
// Lire l'entrée
$shippingType = trim(fgets(STDIN));
$weight = floatval(fgets(STDIN));
// TODO: Créer un ShippingCalculator en commençant avec StandardShipping
// TODO: En fonction du type d'expédition en entrée ("standard", "express", ou "overnight"),
// utiliser setStrategy() pour basculer vers la méthode d'expédition appropriée
// TODO: Calculer le coût pour le poids donné
// TODO: Afficher le résultat formaté à deux décimales
// Output format: Shipping cost: $[cost]
?>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