Menu
Coddy logo textTech

Dekorierermuster

Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy. Lektion 77 von 91.

Das Decorator Pattern ist ein strukturelles Entwurfsmuster, mit dem du Objekten dynamisch neue Verhaltensweisen hinzufügen kannst, indem du sie in spezielle Wrapper-Objekte einhüllst, die als Decorators bezeichnet werden. Im Gegensatz zur Vererbung, die Verhalten zur Kompilierungszeit hinzufügt, fügen Decorators Verhalten zur Laufzeit hinzu.

Stell dir ein Café vor. Du beginnst mit einem einfachen Kaffee und fügst dann Extras wie Milch, Zucker oder Schlagsahne hinzu.

Jede Ergänzung umschließt den ursprünglichen Kaffee und erweitert seine Beschreibung und Kosten. Die entscheidende Erkenntnis ist, dass sowohl der Basiskaffee als auch die Dekorierer dieselbe Schnittstelle verwenden.

<?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;
    }
}

Dekoratoren implementieren dieselbe Schnittstelle und umschließen ein anderes Coffee-Objekt:

<?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();

Output:

Simple Coffee, Milk, Sugar = $2.75

Jeder Decorator umschließt das vorherige Objekt und bildet so eine Kette. Das Muster ermöglicht es dir, Verhaltensweisen in beliebiger Reihenfolge und Anzahl zu kombinieren, ohne für jede mögliche Kombination eine Klasse erstellen zu müssen. Du brauchst doppelte Milch? Umschließe es einfach zweimal.

challenge icon

Aufgabe

Einfach

Lass uns ein Pizza-Bestellsystem mit dem Decorator-Muster erstellen. Du beginnst mit einer einfachen Pizza und fügst dynamisch Beläge hinzu: Jeder Belag umschließt die Pizza und ergänzt ihre Beschreibung und ihren Preis, genau wie im Kaffee-Beispiel aus der Lektion.

Du organisierst deinen Code über vier Dateien:

  • Pizza.php: Definiere ein Pizza-Interface, das den Vertrag für alle Pizzen und Beläge festlegt. Es sollte zwei Methoden haben: getDescription(): string und getPrice(): float.
  • BasePizza.php: Binde das Pizza-Interface ein und erstelle eine MargheritaPizza-Klasse, die dieses implementiert. Dies ist deine Basispizza mit der Beschreibung "Margherita" und einem Preis von 8.00.
  • Toppings.php: Binde das Pizza-Interface ein und erstelle drei Decorator-Klassen, die dieses implementieren. Jeder Decorator umschließt ein Pizza-Objekt (übergebe es im Konstruktor) und erweitert sowohl die Beschreibung als auch den Preis:
    • CheeseTopping: Fügt der Beschreibung ", Extra Cheese" und dem Preis 1.50 hinzu
    • PepperoniTopping: Fügt der Beschreibung ", Pepperoni" und dem Preis 2.00 hinzu
    • MushroomTopping: Fügt der Beschreibung ", Mushrooms" und dem Preis 1.25 hinzu
  • main.php: Binde die Dateien BasePizza und Toppings ein. Du erhältst eine Eingabe: eine durch Kommas getrennte Liste von Belägen, die hinzugefügt werden sollen (z. B. "cheese,pepperoni" oder "mushroom,cheese,cheese").

    Beginne mit einer MargheritaPizza. Umschließe deine Pizza für jeden Belag in der Eingabe mit dem passenden Decorator:

    • "cheese" umschließt sie mit CheeseTopping
    • "pepperoni" umschließt sie mit PepperoniTopping
    • "mushroom" umschließt sie mit MushroomTopping

    Gib nach dem Anwenden aller Beläge die Beschreibung und den Preis der fertigen Pizza in diesem Format aus:

    [description] = $[price]

    Formatiere den Preis mit zwei Dezimalstellen.

Beachte, dass derselbe Belag mehrmals angewendet werden kann: Doppelter Käse bedeutet einfach, dass die Pizza zweimal mit CheeseTopping umschlossen wird. Diese Flexibilität ist die Stärke des Decorator-Musters!

Probier es selbst

<?php
require_once 'BasePizza.php';
require_once 'Toppings.php';

// Eingabe lesen - kommagetrennte Liste von Belägen
$input = trim(fgets(STDIN));
$toppings = explode(',', $input);

// Beginne mit einer Basis-MargheritaPizza
$pizza = new MargheritaPizza();

// TODO: Durchlaufe jeden Belag und umhülle die Pizza mit dem entsprechenden Decorator
// - "cheese" -> mit CheeseTopping umhüllen
// - "pepperoni" -> mit PepperoniTopping umhüllen
// - "mushroom" -> mit MushroomTopping umhüllen

// TODO: Gib das Ergebnis im Format aus: [description] = $[price]
// Formatiere den Preis auf 2 Dezimalstellen mit number_format()

?>
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

Übe selbstständig: Online-PHP-Compiler