Strukturmuster
Adapter
Zwei Seiten passen nicht zusammen: Der eigene Code erwartet eine Schnittstelle, die Bibliothek oder das Altsystem bietet eine andere. Der Adapter ist die dünne Schicht dazwischen — er erfüllt die eigene Schnittstelle und übersetzt die Aufrufe auf das, was die Gegenseite versteht.
Struktur
Die eigene Anwendung definiert die Schnittstelle nach ihrem Bedarf. Der Adapter implementiert sie und hält die fremde Klasse als Feld.
// Vom eigenen Code aus gedacht — nicht von der Bibliothek her.
interface Zahlungsabwicklung
{
public function belasten(Betrag $betrag, Zahlungsmittel $mittel): Zahlungsbeleg;
}
final class FremdanbieterAdapter implements Zahlungsabwicklung
{
public function __construct(private readonly VendorSdkClient $sdk) {}
public function belasten(Betrag $betrag, Zahlungsmittel $mittel): Zahlungsbeleg
{
$antwort = $this->sdk->charge($betrag->cents, $mittel->token(), ['currency' => 'EUR']);
return match ($antwort->status) {
'ok' => Zahlungsbeleg::erfolgreich($antwort->reference),
'declined'=> throw new ZahlungAbgelehnt($antwort->reason),
default => throw new ZahlungFehlgeschlagen($antwort->reason),
};
}
}
Die Übersetzung betrifft nicht nur Methodennamen. Fehlerbehandlung, Datentypen und Einheiten gehören genauso dazu — sonst leckt die Fremdwelt trotz Adapter durch.
Praxisnotiz
Der Adapter ist das Muster, das in Modernisierungen am meisten trägt. In fast jedem schrittweisen Ablösevorhaben steht an der Naht zwischen Alt und Neu einer. Er ist der Grund, warum ein Umbau überhaupt in Etappen möglich ist: Solange die Schnittstelle stabil bleibt, kann dahinter erst das Altsystem und später der Neubau stehen — und beide Zustände sind lauffähig.
Der entscheidende Punkt ist die Richtung des Entwurfs. Die Schnittstelle muss aus der Sicht der eigenen Domäne entstehen, nicht als Spiegelbild des SDK. Ich sehe regelmäßig Adapter, deren Methoden exakt so heißen wie die der Bibliothek und deren Rückgabetypen deren Datenklassen sind. Das ist kein Adapter, das ist ein Weiterreichen mit zusätzlicher Datei — beim Anbieterwechsel ändert sich trotzdem alles.
Ein guter Prüfstein: Kommt in der Anwendung außerhalb des Adapters noch ein Typ, eine Konstante oder eine Ausnahme des Fremdsystems vor? Wenn ja, ist die Grenze nicht dicht. Zweiter Prüfstein: Lässt sich der Adapter im Test durch eine einfache Attrappe ersetzen, ohne dass die Attrappe das SDK nachbauen muss?
Wann es nicht passt
-
Wenn die fremde Schnittstelle bereits passt. Ein Adapter, der nur durchreicht, ist Ballast — und suggeriert eine Entkopplung, die es nicht gibt.
-
Wenn er zur Sammelstelle wird: Sobald im Adapter Fachlogik landet (Preisberechnung, Regeln, Workflows), gehört sie in die Domäne.
-
Bei mehr als einer Fremdwelt hinter einer Fassade — das ist eher ein Fall für die Facade oder für ein eigenes Anti-Corruption-Layer mit Modell.