Sobes.tech
Middle

Wie funktioniert ein Decorator in PHP?

sobes.tech KI

Antwort von AI

Das Muster "Decorator" fügt einem bestehenden Objekt dynamisch ein neues Verhalten hinzu, indem es es in ein anderes Objekt, den sogenannten Decorator, einwickelt.

  • Komponenten:

    • Schnittstelle (Component): Deklariert gemeinsame Methoden für das ursprüngliche Objekt und seine Decorators.
    • Konkretes Component (Concrete Component): Das Hauptobjekt, das dekoriert werden soll.
    • Basisecorator (Decorator): Abstrakte Klasse oder Schnittstelle, die eine Referenz auf ein Objekt der Schnittstelle (Component) enthält und seine Methoden implementiert, meist durch Delegation.
    • Konkrete Decorators (Concrete Decorators): Implementieren neue Funktionen, die das Verhalten des Basiskomponents ergänzen oder ändern.
  • Funktionsprinzip:

    • Der Decorator enthält eine Referenz auf das Objekt, das er dekoriert (Komposition).
    • Der Decorator hat die gleiche Schnittstelle wie das dekorierte Objekt.
    • Beim Aufruf einer Methode beim Decorator führt dieser entweder zusätzliche Logik vor oder nach dem Aufruf der entsprechenden Methode beim dekorierten Objekt aus, oder ersetzt sie vollständig (letzteres ist jedoch keine typische Verwendung).
  • Vorteile:

    • Ermöglicht das Hinzufügen von Funktionalitäten zu Objekten zur Laufzeit, nicht statisch durch Vererbung.
    • Vermeidet die "Explosion" der Klassenhierarchie bei der Kombination verschiedener Verhaltensweisen.
    • Ermöglicht flexible Kombinationen von Verhaltensweisen.
  • Beispiel:

<?php

// Schnittstelle des Components
interface Coffee {
    public function getCost(): float;
    public function getDescription(): string;
}

// Konkretes Component
class SimpleCoffee implements Coffee {
    public function getCost(): float {
        return 5.0;
    }

    public function getDescription(): string {
        return "Einfacher Kaffee";
    }
}

// Basisecorator
abstract class CoffeeDecorator implements Coffee {
    protected Coffee $coffee;

    public function __construct(Coffee $coffee) {
        $this->coffee = $coffee;
    }

    public function getCost(): float {
        return $this->coffee->getCost();
    }

    public function getDescription(): string {
        return $this->coffee->getDescription();
    }
}

// Konkreter Decorator: Milch hinzufügen
class MilkDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 2.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", mit Milch";
    }
}

// Konkreter Decorator: Zucker hinzufügen
class SugarDecorator extends CoffeeDecorator {
    public function getCost(): float {
        return parent::getCost() + 1.0;
    }

    public function getDescription(): string {
        return parent::getDescription() . ", mit Zucker";
    }
}

// Verwendung:
// Einfachen Kaffee erstellen
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . " - " . $coffee->getCost() . "\n"; // Einfacher Kaffee - 5

// Milch hinzufügen
$coffeeWithMilk = new MilkDecorator($coffee);
echo $coffeeWithMilk->getDescription() . " - " . $coffeeWithMilk->getCost() . "\n"; // Einfacher Kaffee, mit Milch - 7

// Zucker hinzufügen
$coffeeWithMilkAndSugar = new SugarDecorator($coffeeWithMilk);
echo $coffeeWithMilkAndSugar->getDescription() . " - " . $coffeeWithMilkAndSugar->getCost() . "\n"; // Einfacher Kaffee, mit Milch, mit Zucker - 8