Menu
Coddy logo textTech

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
80

Das 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.

challenge icon

Aufgabe

Einfach

Lassen 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 ein ShippingStrategy-Interface, das den Vertrag für alle Versandmethoden definiert. Es sollte eine Methode calculate(float $weight): float haben, 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.00 unabhängig vom Gewicht
    • ExpressShipping — Berechnet $2.00 pro Kilogramm (Gewicht multipliziert mit 2)
    • OvernightShipping — Berechnet eine Grundgebühr von $10.00 plus $3.00 pro Kilogramm
  • ShippingCalculator.php — Binden Sie die ShippingStrategy-Datei ein und erstellen Sie eine ShippingCalculator-Klasse, die als Kontext fungiert. Ihr Rechner sollte:
    • Eine ShippingStrategy in 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
  • 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 mit StandardShipping. Verwenden Sie basierend auf der Eingabe des Versandtyps setStrategy(), 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); // 80

Das 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]

?>
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung