Strukturelle Muster: Adapter, Decorator, Facade
Kombinieren Sie Objekte und vereinfachen Sie Schnittstellen mit strukturellen Mustern.
Strukturelle Muster: Adapter, Decorator, Facade ist eine kostenlose PHP Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des PHP Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Objekte zusammensetzen
Strukturmuster beschreiben, wie Klassen und Objekte zu größeren Strukturen zusammengesetzt werden, ohne ihre Flexibilität einzuschränken. Wir behandeln drei besonders wichtige Muster:
- Adapter — eine inkompatible Schnittstelle nutzbar machen.
- Decorator — Verhalten hinzufügen, ohne Unterklassen zu bilden.
- Facade — eine einfache Oberfläche für ein komplexes Subsystem bereitstellen.
Adapter: das Problem
Sie hängen von einer PaymentGateway-Schnittstelle ab, aber ein SDK eines Drittanbieters stellt chargeCard($amountInCents) mit einer anderen Form bereit. Wenn Sie das SDK direkt aufrufen, wird seine API überall im Code sichtbar. Unten sind die beiden Schnittstellen eindeutig inkompatibel — genau diese Diskrepanz löst ein Adapter.
<?php
// What our app wants to depend on
interface PaymentGateway { public function pay(float $dollars): string; }
// What the vendor actually gives us (cents, array result)
final class StripeSdk {
public function chargeCard(int $cents): array {
return ['id' => 'ch_1', 'amount' => $cents];
}
}
// dollars vs cents, string vs array -> shapes don't line up
var_dump((new StripeSdk())->chargeCard(2000));
Adapter im Code
Der Adapter enthält das adaptierte Objekt und implementiert Ihre Ziel-Schnittstelle, wobei er Argumente und Rückgabewerte konvertiert. Ihr Anwendungscode bleibt sauber und unabhängig vom Anbieter.
<?php
interface PaymentGateway { public function pay(float $dollars): string; }
// Third-party SDK with an incompatible API
final class StripeSdk {
public function chargeCard(int $cents): array {
return ['id' => 'ch_1', 'amount' => $cents];
}
}
final class StripeAdapter implements PaymentGateway {
public function __construct(private StripeSdk $sdk) {}
public function pay(float $dollars): string {
$res = $this->sdk->chargeCard((int) round($dollars * 100));
return "charged {$res['amount']}c -> {$res['id']}";
}
}
echo (new StripeAdapter(new StripeSdk()))->pay(20.0), PHP_EOL;
Decorator: die Idee
Ein Decorator umschließt ein Objekt mit derselben Schnittstelle und fügt vor oder nach der Delegation Verhalten hinzu. Anders als bei Vererbung lassen sich Decorators zur Laufzeit stapeln. So können Sie Funktionen in beliebiger Reihenfolge kombinieren, ohne dass die Anzahl der Klassen explodiert. Hier ist das minimale Grundgerüst: ein Wrapper, der dieselbe Schnittstelle implementiert und die innere Instanz enthält.
<?php
interface Coffee { public function cost(): float; }
final class Espresso implements Coffee {
public function cost(): float { return 2.0; }
}
final class WithMilk implements Coffee {
public function __construct(private Coffee $inner) {}
public function cost(): float { return $this->inner->cost() + 0.5; }
}
echo (new WithMilk(new Espresso()))->cost(), PHP_EOL; // 2.5
Decorator im Code
Jeder Decorator implementiert dieselbe Schnittstelle und enthält eine innere Instanz. Hier umschließen wir eine Datenquelle mit Caching und Logging und kombinieren beides frei.
<?php
interface DataSource { public function read(): string; }
final class FileSource implements DataSource {
public function read(): string { return 'raw-data'; }
}
final class UpperCaseDecorator implements DataSource {
public function __construct(private DataSource $inner) {}
public function read(): string { return strtoupper($this->inner->read()); }
}
final class ExclaimDecorator implements DataSource {
public function __construct(private DataSource $inner) {}
public function read(): string { return $this->inner->read() . '!!!'; }
}
$src = new ExclaimDecorator(new UpperCaseDecorator(new FileSource()));
echo $src->read(), PHP_EOL; // RAW-DATA!!!
Decorators in der Praxis
PSR-7-/PSR-15-Middleware ist im Wesentlichen das Decorator-Muster, angewendet auf die HTTP-Verarbeitung: Jede Middleware umschließt die nächste und fügt Authentifizierung, Logging oder Caching rund um Request und Response hinzu. Auch Stream-Wrapper und PSR-6-/PSR-16-Cache-Schichten verwenden häufig Dekoration. Das entscheidende Merkmal: Der Wrapper kann anstelle des von ihm umschlossenen Objekts verwendet werden.
Decorator oder Vererbung
Vererbung legt das Verhalten zur Compile-Zeit fest und erlaubt nur eine Basisklasse. Dekoration ist dynamisch und kombinierbar. Wählen Sie Decorators, wenn:
- die Kombinationen optionaler Funktionen stark zunehmen,
- Verhalten zur Laufzeit hinzugefügt oder entfernt werden soll,
- Sie eine
final- oder Drittanbieterklasse erweitern müssen, von der Sie nicht ableiten können.
Facade: die Idee
Eine Facade stellt einen einzigen, vereinfachten Einstiegspunkt in ein komplexes Subsystem aus vielen Klassen bereit. Sie verbirgt das Subsystem nicht (Sie können weiterhin direkt darauf zugreifen), bietet aber für den häufigsten Anwendungsfall eine bequeme API auf höherer Ebene. Vergleichen Sie die ausführliche Interaktion mit dem Subsystem unten mit dem einzeiligen Facade-Aufruf in der nächsten Szene.
<?php
// Without a facade, the client wires every step itself
final class Cpu { public function boot(): string { return 'cpu '; } }
final class Disk { public function load(): string { return 'disk '; } }
final class Ram { public function check(): string { return 'ram'; } }
$out = (new Cpu())->boot() . (new Disk())->load() . (new Ram())->check();
echo $out, PHP_EOL; // cpu disk ram
Facade im Code
Die Facade koordiniert mehrere Mitwirkende hinter einer einzigen Methode. Clients rufen place() auf, anstatt Inventar, Zahlung und Versand selbst zu verdrahten.
<?php
final class Inventory { public function reserve(string $sku): bool { return true; } }
final class Payments { public function charge(float $amt): bool { return true; } }
final class Shipping { public function dispatch(string $sku): string { return 'tracking-99'; } }
final class OrderFacade {
public function __construct(
private Inventory $inv,
private Payments $pay,
private Shipping $ship
) {}
public function place(string $sku, float $amount): string {
if (!$this->inv->reserve($sku)) { return 'out of stock'; }
if (!$this->pay->charge($amount)) { return 'payment failed'; }
return 'shipped: ' . $this->ship->dispatch($sku);
}
}
echo (new OrderFacade(new Inventory(), new Payments(), new Shipping()))
->place('ABC', 49.99), PHP_EOL;
Die drei Muster unterscheiden
- Adapter ändert eine Schnittstelle, damit zwei bestehende Bestandteile miteinander kommunizieren können; das Verhalten bleibt gleich, nur die Form ist anders.
- Decorator behält die Schnittstelle bei, fügt aber zur Laufzeit stapelbares Verhalten hinzu.
- Facade führt vor vielen Klassen eine neue, einfachere Schnittstelle ein.
Eine hilfreiche Faustregel: Beim Adapter geht es um Kompatibilität, beim Decorator um Erweiterung und bei der Facade um Vereinfachung.
Hinweis zu Laravel-Facades
Die „Facades“ von Laravel sind ein Mechanismus für statische Proxys, der vom Service-Container unterstützt wird, und nicht das GoF-Facade-Muster. Sie verfolgen dasselbe Ziel einer bequemen Oberfläche, unterscheiden sich aber in der Implementierung. Vermischen Sie bei der Beurteilung des Designs die Framework-Terminologie nicht mit dem Strukturmuster.
Schnelltest
Identifizieren Sie das Muster anhand seiner Absicht.
Zusammenfassung
Sie haben Objekte mit drei Strukturmustern zusammengesetzt: Adapter, um inkompatible Schnittstellen zu verbinden (z. B. ein SDK eines Anbieters), Decorator, um Verhalten zur Laufzeit zu stapeln (die Grundlage von PSR-15-Middleware), und Facade, um eine einfache Oberfläche vor ein komplexes Subsystem zu setzen. Jedes Muster reduziert die Kopplung, sodass Ihr Code widerstandsfähiger gegen Vendor-Lock-in und eine übermäßige Ausweitung von Funktionen wird.
Häufig gestellte Fragen
Ist die Lektion „Strukturelle Muster: Adapter, Decorator, Facade“ kostenlos?
Ja — der vollständige Text von „Strukturelle Muster: Adapter, Decorator, Facade“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des PHP Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Strukturelle Muster: Adapter, Decorator, Facade“?
Kombinieren Sie Objekte und vereinfachen Sie Schnittstellen mit strukturellen Mustern. Du übst PHP Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um PHP Academy zu starten?
Keine Vorkenntnisse erforderlich. PHP Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Strukturelle Muster: Adapter, Decorator, Facade“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser PHP Academy-Lektion Code schreiben und ausführen?
Ja. Jede PHP Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- SOLID-Prinzipien in der Praxis
- Erzeugungsmuster: Factory, Builder, Singleton
- Strukturelle Muster: Adapter, Decorator, Facade
- Verhaltensmuster: Strategy, Observer, Command