Strategy-Muster
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 74 von 91.
Das Strategy-Pattern ist ein Verhaltensmuster, mit dem Sie eine Familie von Algorithmen definieren, jeden einzelnen in einer eigenen Klasse kapseln und sie zur Laufzeit austauschbar machen können. Das Objekt, das die Strategie verwendet, muss nicht wissen, welcher Algorithmus gerade ausgeführt wird.
Stellen Sie sich einen Warenkorb vor, der verschiedene Rabattstrategien anwenden kann. Anstatt die Rabattlogik mit Bedingungen fest zu verdrahten (hardcoding), definieren Sie jeden Rabatt als eine separate Klasse:
<?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);
}
}
Die Kontext-Klasse akzeptiert jede Strategie und delegiert die Berechnung:
<?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);
Ausgabe:
100
80Das Strategy-Pattern glänzt, wenn Sie mehrere Möglichkeiten haben, eine Operation auszuführen, und zwischen ihnen wechseln möchten, ohne die Klasse zu ändern, die sie verwendet. Das Hinzufügen eines neuen Rabatttyps bedeutet das Erstellen einer neuen Klasse, ohne den bestehenden Code anzurühren.
Aufgabe
EinfachLassen Sie uns einen Versandkostenrechner mit dem Strategy Pattern erstellen. Verschiedene Versandarten haben unterschiedliche Preisregeln — der Standardversand berechnet eine Pauschale, der Expressversand fügt einen Prozentsatz hinzu und der Übernachtversand kombiniert beides. Das Strategy Pattern ermöglicht es Ihnen, diese Berechnungen auszutauschen, ohne den Code zu ändern, der sie verwendet.
Sie werden Ihren Code in vier Dateien organisieren:
ShippingStrategy.php— Erstellen Sie einShippingStrategy-Interface, das den Vertrag für alle Versandmethoden definiert. Es sollte eine Methodecalculate(float $weight): floathaben, die das Paketgewicht entgegennimmt und die Versandkosten zurückgibt.ShippingMethods.php— Binden Sie die ShippingStrategy-Datei ein und erstellen Sie drei Klassen, die das Interface implementieren:StandardShipping— Berechnet eine Pauschale von$5.00unabhängig vom GewichtExpressShipping— Berechnet$2.00pro Kilogramm (Gewicht multipliziert mit 2)OvernightShipping— Berechnet eine Grundgebühr von$10.00plus$3.00pro Kilogramm
ShippingCalculator.php— Binden Sie die ShippingStrategy-Datei ein und erstellen Sie eineShippingCalculator-Klasse, die als Kontext fungiert. Ihr Rechner sollte:- Eine
ShippingStrategyin seinem Konstruktor akzeptieren (verwenden Sie Constructor Promotion) - Eine
setStrategy(ShippingStrategy $strategy): void-Methode haben, um die Versandmethode zur Laufzeit zu ändern - Eine
calculateCost(float $weight): float-Methode haben, die an die aktuelle Strategie delegiert
- Eine
main.php— Binden Sie die Dateien ShippingMethods und ShippingCalculator ein. Sie erhalten zwei Eingaben: einen Versandtyp ("standard","express"oder"overnight") und ein Paketgewicht.Erstellen Sie einen
ShippingCalculator, beginnend mitStandardShipping. Verwenden Sie basierend auf der Eingabe des VersandtypssetStrategy(), um zur entsprechenden Versandmethode zu wechseln. Berechnen Sie dann die Kosten für das angegebene Gewicht und geben Sie das Ergebnis auf zwei Dezimalstellen formatiert aus.Die Ausgabe sollte sein:
Shipping cost: $[cost]
Diese Herausforderung zeigt, wie das Strategy Pattern Ihr Versandsystem flexibel macht — das Hinzufügen einer neuen Versandmethode wie SameDayShipping erfordert nur das Erstellen einer neuen Klasse, die das Interface implementiert, ohne den Rechner oder bestehende Versandmethoden anzupassen.
Spickzettel
Das Strategy Pattern (Strategiemuster) ist ein Verhaltensmuster, das eine Familie von Algorithmen definiert, jeden einzelnen in einer eigenen Klasse kapselt und sie zur Laufzeit austauschbar macht.
Definieren Sie ein Interface für die Strategie:
<?php
interface DiscountStrategy {
public function calculate(float $total): float;
}Implementieren Sie konkrete Strategien:
<?php
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);
}
}Erstellen Sie eine Kontext-Klasse, die die Strategie verwendet:
<?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);
}
}Verwenden Sie das Muster, indem Sie Strategien injizieren:
<?php
$cart = new ShoppingCart(new NoDiscount());
echo $cart->checkout(100); // 100
$cart->setDiscount(new PercentageDiscount(20));
echo $cart->checkout(100); // 80Das Strategy Pattern ermöglicht es Ihnen, zwischen Algorithmen zu wechseln, ohne die Klasse zu ändern, die sie verwendet. Das Hinzufügen neuer Strategien erfordert lediglich das Erstellen neuer Klassen, die das Interface implementieren.
Probier es selbst
<?php
require_once 'ShippingMethods.php';
require_once 'ShippingCalculator.php';
// Eingabe lesen
$shippingType = trim(fgets(STDIN));
$weight = floatval(fgets(STDIN));
// TODO: Erstellen Sie einen ShippingCalculator beginnend mit StandardShipping
// TODO: Basierend auf der Eingabe der Versandart ("standard", "express" oder "overnight"),
// verwenden Sie setStrategy(), um zur entsprechenden Versandmethode zu wechseln
// TODO: Berechnen Sie die Kosten für das angegebene Gewicht
// TODO: Geben Sie das Ergebnis auf zwei Dezimalstellen formatiert aus
// Ausgabeformat: Shipping cost: $[cost]
?>Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas $this-SchlüsselwortMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick - Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDas parent:: SchlüsselwortMethoden überschreibenDas final SchlüsselwortAbstrakte KlassenZusammenfassung – Mitarbeiter-Hierarchie7Kapselung
Public, Protected, PrivateZugriffsmodifikatoren im DetailGetter und SetterInformation HidingConstructor Promotion (8.0)Zusammenfassung – Studentenverwaltungssystem2Namensräume & Autoloading
Einführung in NamensräumeDas use-SchlüsselwortPSR-4 Autoloading-StandardComposer AutoloaderZusammenfassung – Organisiertes Projekt5Interfaces & Verträge
Einführung in InterfacesInterfaces implementierenMehrfache Interface-ImplementierungInterface vs. Abstrakte KlasseType Hinting mit InterfacesZusammenfassung – Formen-Rechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objekt-Klonen__serialize & __unserializeZusammenfassung - Eigene Collection11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenEigene Exception-HierarchieTry, Catch, FinallyZusammenfassung - Formular-Validator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klasseneigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenReadonly-Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphismus
Method Overriding erneut betrachtetPolymorphismus über InterfacesType Hinting & Union TypesLate Static BindingZusammenfassung – Payment Processor9Traits
Einführung in TraitsVerwendung mehrerer TraitsKonfliktlösung bei TraitsAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung