Menu
Coddy logo textTech

Adapter-Muster

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 71 von 87.

Das Adapter-Muster ist ein Strukturmuster, das es inkompatiblen Schnittstellen ermöglicht, zusammenzuarbeiten. Es fungiert als Brücke zwischen zwei Klassen und wandelt die Schnittstelle einer Klasse in eine Schnittstelle um, die der Client erwartet. Stellen Sie es sich wie einen Reiseadapter vor, mit dem Sie ein europäisches Gerät an eine amerikanische Steckdose anschließen können.

Stellen Sie sich vor, Sie haben eine bestehende MediaPlayer-Schnittstelle, die Audiodateien abspielt, aber Sie müssen eine Bibliothek eines Drittanbieters integrieren, die eine völlig andere Schnittstelle zum Abspielen von Videos verwendet:

// Vorhandene Schnittstelle, die Ihr Code verwendet
interface MediaPlayer {
    void play(String filename);
}

// Drittanbieter-Klasse mit inkompatibler Schnittstelle
class AdvancedVideoPlayer {
    public void playVideo(String filename) {
        System.out.println("Playing video: " + filename);
    }
}

Der Adapter kapselt die inkompatible Klasse und implementiert die erwartete Schnittstelle, wobei er Aufrufe zwischen ihnen übersetzt:

class VideoPlayerAdapter implements MediaPlayer {
    private AdvancedVideoPlayer videoPlayer;
    
    public VideoPlayerAdapter() {
        this.videoPlayer = new AdvancedVideoPlayer();
    }
    
    public void play(String filename) {
        videoPlayer.playVideo(filename);
    }
}

Jetzt kann Ihr Client-Code den Videoplayer über die vertraute MediaPlayer-Schnittstelle verwenden:

MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4");  // Ausgabe: Video wird abgespielt: movie.mp4

Das Adapter-Muster ist von unschätzbarem Wert, wenn Legacy-Code oder Bibliotheken von Drittanbietern integriert werden sollen, ohne deren Quellcode zu ändern. Der Client merkt nicht, dass er mit einer angepassten Klasse arbeitet – er verwendet einfach die Schnittstelle, die er kennt.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Temperaturkonvertierungssystem mit dem Adapter-Pattern bauen! Sie haben eine bestehende Wetteranwendung, die mit Celsius-Temperaturen arbeitet, aber Sie müssen einen alten Temperatursensor integrieren, der nur Messwerte in Fahrenheit ausgibt. Anstatt eines der beiden Systeme zu modifizieren, erstellen Sie einen Adapter, der die Lücke schließt.

Sie werden Ihren Code über vier Dateien organisieren:

  • TemperatureProvider.java: Definieren Sie das Interface, das Ihre Wetteranwendung erwartet. Es sollte eine Methode getTemperatureCelsius() deklarieren, die einen double-Wert zurückgibt, der die Temperatur in Celsius darstellt.
  • FahrenheitSensor.java: Dies repräsentiert den alten Sensor mit einem inkompatiblen Interface. Erstellen Sie eine Klasse mit einem privaten double-Feld für die Temperatur in Fahrenheit, das über den Konstruktor gesetzt wird. Sie sollte eine Methode readFahrenheit() haben, die den gespeicherten Fahrenheit-Wert zurückgibt.
  • SensorAdapter.java: Erstellen Sie den Adapter, der den Fahrenheit-Sensor mit Ihrer Wetteranwendung kompatibel macht. Ihr Adapter sollte TemperatureProvider implementieren und einen FahrenheitSensor kapseln. Wenn getTemperatureCelsius() aufgerufen wird, sollte er den Wert vom Sensor lesen und ihn mit der Formel (fahrenheit - 32) * 5 / 9 in Celsius umrechnen.
  • Main.java: Bringen Sie alles zusammen! Sie erhalten eine Eingabe: einen Temperaturmesswert in Fahrenheit (double).

    Erstellen Sie einen FahrenheitSensor mit dem Eingabewert. Erstellen Sie dann einen SensorAdapter, der diesen Sensor kapselt. Speichern Sie den Adapter in einer TemperatureProvider-Variable, um zu demonstrieren, dass Ihre Wetteranwendung ihn über das erwartete Interface nutzen kann.

    Geben Sie das Ergebnis in diesem Format aus: "Temperature: " + String.format("%.1f", celsius) + " C", wobei celsius auf eine Dezimalstelle formatiert ist.

Sie erhalten eine Eingabe: die Fahrenheit-Temperatur (double).

Zum Beispiel, bei der Eingabe 98.6, wäre Ihre Ausgabe:

Temperature: 37.0 C

Beachten Sie, wie Ihre Main-Klasse vollständig mit dem TemperatureProvider-Interface arbeitet – sie hat keine Ahnung, dass die tatsächliche Temperatur von einem Fahrenheit-Sensor stammt, der hinter den Kulissen angepasst wird. Das ist die Eleganz des Adapter-Patterns!

Spickzettel

Das Adapter-Muster (Adapter Pattern) ist ein Strukturmuster, das es inkompatiblen Schnittstellen ermöglicht, zusammenzuarbeiten, indem es als Brücke zwischen zwei Klassen fungiert und eine Schnittstelle in eine andere umwandelt, die der Client erwartet.

Schlüsselkomponenten

  • Target Interface (Ziel-Schnittstelle): Die Schnittstelle, die der Client zu verwenden erwartet
  • Adaptee (Dienst): Die bestehende Klasse mit einer inkompatiblen Schnittstelle
  • Adapter: Die Klasse, die die Ziel-Schnittstelle implementiert und den Dienst (Adaptee) kapselt, wobei sie die Aufrufe zwischen ihnen übersetzt

Grundstruktur

// Target interface
interface MediaPlayer {
    void play(String filename);
}

// Adaptee (incompatible class)
class AdvancedVideoPlayer {
    public void playVideo(String filename) {
        System.out.println("Playing video: " + filename);
    }
}

// Adapter
class VideoPlayerAdapter implements MediaPlayer {
    private AdvancedVideoPlayer videoPlayer;
    
    public VideoPlayerAdapter() {
        this.videoPlayer = new AdvancedVideoPlayer();
    }
    
    public void play(String filename) {
        videoPlayer.playVideo(filename);
    }
}

// Client usage
MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4");  // Output: Playing video: movie.mp4

Wann man es verwendet

Das Adapter-Muster ist nützlich, wenn:

  • Legacy-Code oder Bibliotheken von Drittanbietern integriert werden sollen, ohne deren Quellcode zu ändern
  • Inkompatible Schnittstellen zur Zusammenarbeit gebracht werden müssen
  • Der Client keine Kenntnis von der angepassten Implementierung haben soll

Probier es selbst

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double fahrenheit = scanner.nextDouble();
        
        // TODO: Erstelle einen FahrenheitSensor mit dem Eingabewert
        
        // TODO: Erstelle einen SensorAdapter, der den Sensor umschließt
        
        // TODO: Speichere den Adapter in einer TemperatureProvider Variable
        
        // TODO: Rufe die Temperatur in Celsius ab und gib sie aus
        // Format: "Temperature: [celsius] C" mit einer Dezimalstelle
        // Hinweis: Verwende String.format("%.1f", value) für die Formatierung
    }
}
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