Adaptermuster
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 71 von 87.
Das Adapter-Muster ist ein strukturelles Entwurfsmuster, 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. Stell es dir wie einen Netzadapter vor, mit dem du ein europäisches Gerät an eine amerikanische Steckdose anschließen kannst.
Stell dir vor, du hast eine vorhandene MediaPlayer-Schnittstelle, die Audiodateien abspielt, aber du musst eine Bibliothek eines Drittanbieters integrieren, die zum Abspielen von Videos eine völlig andere Schnittstelle verwendet:
// Bestehende Schnittstelle, die dein 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 umschließt 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 dein Client-Code den Videoplayer über die vertraute MediaPlayer-Schnittstelle verwenden:
MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4"); // Ausgabe: Playing video: movie.mp4Das Adapter-Muster ist von unschätzbarem Wert, wenn du Legacy-Code oder Bibliotheken von Drittanbietern integrierst, ohne deren Quellcode zu ändern. Der Client weiß nicht, dass er mit einer adaptierten Klasse arbeitet. Er verwendet einfach die Schnittstelle, die er kennt.
Aufgabe
EinfachErstellen wir ein Temperaturumrechnungssystem mithilfe des Adapter-Patterns! Du hast eine vorhandene Wetteranwendung, die mit Celsius-Temperaturen arbeitet, musst aber einen veralteten Temperatursensor integrieren, der Messwerte nur in Fahrenheit ausgibt. Anstatt eines der beiden Systeme zu ändern, erstellst du einen Adapter, der die Lücke überbrückt.
Du organisierst deinen Code über vier Dateien:
TemperatureProvider.java: Definiere die Schnittstelle, die deine Wetteranwendung erwartet. Sie sollte eine MethodegetTemperatureCelsius()deklarieren, die einen double zurückgibt, der die Temperatur in Celsius darstellt.FahrenheitSensor.java: Dies stellt den veralteten Sensor mit einer inkompatiblen Schnittstelle dar. Erstelle eine Klasse mit einem privaten double-Feld für die Temperatur in Fahrenheit, das über den Konstruktor gesetzt wird. Sie sollte eine MethodereadFahrenheit()besitzen, die den gespeicherten Fahrenheit-Wert zurückgibt.SensorAdapter.java: Erstelle den Adapter, der den Fahrenheit-Sensor mit deiner Wetteranwendung kompatibel macht. Dein Adapter sollteTemperatureProviderimplementieren und einenFahrenheitSensorkapseln. WenngetTemperatureCelsius()aufgerufen wird, sollte er den Sensor auslesen und den Wert mithilfe der Formel(fahrenheit - 32) * 5 / 9in Celsius umrechnen.Main.java: Führe alles zusammen! Du erhältst eine Eingabe: einen Temperaturmesswert in Fahrenheit (double).Erstelle einen
FahrenheitSensormit dem Eingabewert. Erstelle anschließend einenSensorAdapter, der diesen Sensor kapselt. Speichere den Adapter in einerTemperatureProvider-Variablen, um zu zeigen, dass deine Wetteranwendung ihn über die erwartete Schnittstelle verwenden kann.Gib das Ergebnis in diesem Format aus:
Temperature: [celsius] C, wobei celsius mit einer Dezimalstelle formatiert wird.
Du erhältst eine Eingabe: die Fahrenheit-Temperatur (double).
Bei der Eingabe 98.6 wäre deine Ausgabe beispielsweise:
Temperature: 37.0 CBeachte, dass deine Main-Klasse vollständig mit der Schnittstelle TemperatureProvider arbeitet. Sie weiß nicht, dass die tatsächliche Temperatur von einem Fahrenheit-Sensor stammt, der im Hintergrund adaptiert wird. Das ist die Eleganz des Adapter-Patterns!
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 umhüllt
// TODO: Speichere den Adapter in einer TemperatureProvider-Variable
// TODO: Hole die Temperatur in Celsius und gib sie aus
// Format: "Temperature: [celsius] C" mit einer Dezimalstelle
// Hinweis: Verwende String.format("%.1f", value) zur Formatierung
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenFelder (Attribute)KonstruktormethodeÜberladen von KonstruktorenRückblick – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbung (extends)Das Schlüsselwort superÜberschreiben von Methoden (@Override)KonstruktorverkettungDie Object-KlasseEinfach- und mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenRückblick – Mitarbeiterhierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-SchnittstelleRückblick – Benutzerdefinierte Sortierung2Zugriffsmodifikatoren & Kapselung
Übersicht der ZugriffsebenenGetter- und Setter-MethodenInformationsverbergungDas Schlüsselwort finalRückblick – Bankkontoverwaltung5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, verschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Versiegelte Klassen (Java 17+)11Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBuilder-MusterObserver-MusterStrategie-Muster14Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungsdienst3Klassen-Props & statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Wiederholung – Counter & Utility6Schnittstellen & abstrakte Klassen
Einführung in InterfacesInterfaces implementierenMehrere Interfaces implementierenDefault & Static in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesRückblick – Zahlungssystem9Generics
Einführung in GenericsGenerische KlassenGenerische MethodenGebundene TypparameterWildcards (?, extends, super)Rückblick – Generischer Container12Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterSchablonenmethodenmusterZustandsmusterKompositmusterIteratormusterÜbe selbstständig: Online-Java-Compiler