Menu
Coddy logo textTech

Adapter-Muster

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

Das Adapter-Muster ist ein Strukturmuster, das es Objekten mit inkompatiblen Schnittstellen ermöglicht, zusammenzuarbeiten. Es fungiert als Brücke zwischen zwei Schnittstellen und übersetzt Aufrufe von einem Format in ein anderes.

Stellen Sie sich vor, Sie entwickeln eine Anwendung, die Zahlungen verarbeitet, und Sie müssen eine Zahlungsbibliothek eines Drittanbieters integrieren. Die Bibliothek funktioniert einwandfrei, aber ihre Schnittstelle entspricht nicht dem, was Ihr Code erwartet. Anstatt Ihre gesamte Anwendung umzuschreiben, erstellen Sie einen Adapter, der zwischen den beiden vermittelt.

<?php
// Die Schnittstelle, die Ihre Anwendung erwartet
interface PaymentProcessor {
    public function pay(float $amount): string;
}

// Drittanbieter-Bibliothek mit einer anderen Schnittstelle
class StripeAPI {
    public function createCharge(int $cents, string $currency): string {
        return "Charged {$cents} {$currency} via Stripe";
    }
}

Der Adapter implementiert die von Ihnen erwartete Schnittstelle, während er intern die Klasse des Drittanbieters verwendet:

<?php
class StripeAdapter implements PaymentProcessor {
    public function __construct(private StripeAPI $stripe) {}
    
    public function pay(float $amount): string {
        $cents = (int)($amount * 100);
        return $this->stripe->createCharge($cents, 'USD');
    }
}

$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);

Ausgabe:

Charged 2999 USD via Stripe

Der Adapter konvertiert Dollar in Cent und ruft die entsprechende Methode auf. Ihr Anwendungscode kennt nur PaymentProcessor und bleibt von den spezifischen Anforderungen von Stripe völlig unberührt. Wenn Sie später zu einem anderen Zahlungsanbieter wechseln, erstellen Sie einfach einen neuen Adapter, ohne Ihren bestehenden Code zu ändern.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Temperaturkonvertierungssystem unter Verwendung des Adapter-Musters erstellen. Sie verfügen über einen alten Temperatursensor, der Messwerte in Fahrenheit ausgibt, aber Ihre moderne Wetteranwendung erwartet alle Temperaturen in Celsius. Anstatt eines der beiden Systeme zu modifizieren, erstellen Sie einen Adapter, der die Lücke schließt.

Sie werden Ihren Code über vier Dateien hinweg organisieren:

  • TemperatureSensor.php — Definieren Sie ein TemperatureSensor-Interface, das Ihre Wetteranwendung erwartet. Es sollte eine Methode getTemperature(): float haben, die die Temperatur in Celsius zurückgibt.
  • LegacySensor.php — Erstellen Sie eine LegacySensor-Klasse, die die alte Hardware simuliert. Diese Klasse hat ein anderes Interface als das, was Ihre Anwendung benötigt:
    • Sie nimmt einen Fahrenheit-Messwert in ihrem Konstruktor entgegen (verwenden Sie Constructor Promotion)
    • Sie hat eine Methode readFahrenheit(): float, die den gespeicherten Fahrenheit-Wert zurückgibt
  • LegacySensorAdapter.php — Binden Sie sowohl das TemperatureSensor-Interface als auch die LegacySensor-Klasse ein. Erstellen Sie eine LegacySensorAdapter-Klasse, die TemperatureSensor implementiert und einen LegacySensor kapselt. Ihr Adapter sollte:
    • Einen LegacySensor in seinem Konstruktor akzeptieren
    • getTemperature() implementieren, indem der Fahrenheit-Wert vom Legacy-Sensor gelesen und mit der Formel (fahrenheit - 32) * 5 / 9 in Celsius umgerechnet wird
  • main.php — Binden Sie die Datei LegacySensorAdapter ein. Sie erhalten eine Eingabe: eine Temperatur in Fahrenheit.

    Erstellen Sie einen LegacySensor mit der eingegebenen Temperatur und kapseln Sie ihn dann in einen LegacySensorAdapter. Rufen Sie getTemperature() auf dem Adapter auf und geben Sie das Ergebnis auf zwei Dezimalstellen gerundet aus.

    Das Ausgabeformat sollte sein: Temperature: [celsius]C

Diese Herausforderung zeigt, wie das Adapter-Muster es Ihnen ermöglicht, inkompatible Schnittstellen zu integrieren, ohne bestehenden Code zu ändern. Ihre Wetteranwendung arbeitet ausschließlich mit dem TemperatureSensor-Interface und weiß überhaupt nicht, dass die tatsächlichen Messwerte von einem alten Fahrenheit-Sensor stammen.

Spickzettel

Das Adapter-Muster (Adapter Pattern) ist ein Strukturmuster, das es Objekten mit inkompatiblen Schnittstellen ermöglicht, zusammenzuarbeiten, indem es als Brücke zwischen ihnen fungiert.

Grundstruktur

Definieren Sie die Schnittstelle, die Ihre Anwendung erwartet:

<?php
interface PaymentProcessor {
    public function pay(float $amount): string;
}

Eine Drittanbieter-Klasse mit einer anderen Schnittstelle:

<?php
class StripeAPI {
    public function createCharge(int $cents, string $currency): string {
        return "Charged {$cents} {$currency} via Stripe";
    }
}

Erstellen des Adapters

Der Adapter implementiert die erwartete Schnittstelle, während er intern die Drittanbieter-Klasse verwendet:

<?php
class StripeAdapter implements PaymentProcessor {
    public function __construct(private StripeAPI $stripe) {}
    
    public function pay(float $amount): string {
        $cents = (int)($amount * 100);
        return $this->stripe->createCharge($cents, 'USD');
    }
}

Verwendung

$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);
// Ausgabe: Charged 2999 USD via Stripe

Der Adapter übersetzt zwischen Schnittstellen und ermöglicht es Ihrem Anwendungscode, unverändert zu bleiben, wenn Sie Bibliotheken von Drittanbietern integrieren oder Implementierungen wechseln.

Probier es selbst

<?php
require_once 'LegacySensorAdapter.php';

// Eingabe lesen
$fahrenheit = floatval(trim(fgets(STDIN)));

// TODO: Erstelle einen LegacySensor mit der eingegebenen Temperatur
// TODO: In einen LegacySensorAdapter einhüllen
// TODO: getTemperature() auf dem Adapter aufrufen
// TODO: Das Ergebnis auf zwei Dezimalstellen gerundet ausgeben
// Ausgabeformat: Temperature: [celsius]C

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