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 ein bestehendes MediaPlayer Interface, das Audiodateien abspielt, aber Sie müssen eine Bibliothek eines Drittanbieters integrieren, die ein völlig anderes Interface zum Abspielen von Videos verwendet:
// Vorhandenes Interface, das Ihr Code verwendet
interface MediaPlayer {
void play(String filename);
}
// Drittanbieter-Klasse mit inkompatiblem Interface
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.mp4Das Adapter-Muster ist von unschätzbarem Wert, wenn es darum geht, Legacy-Code oder Bibliotheken von Drittanbietern zu integrieren, ohne deren Quellcode zu ändern. Der Client merkt nicht, dass er mit einer angepassten Klasse arbeitet – er verwendet einfach die Schnittstelle, die er kennt.
Aufgabe
EinfachLassen 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 MethodegetTemperatureCelsius()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 MethodereadFahrenheit()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 sollteTemperatureProviderimplementieren und einenFahrenheitSensorkapseln. WenngetTemperatureCelsius()aufgerufen wird, sollte er den Wert vom Sensor lesen und ihn mit der Formel(fahrenheit - 32) * 5 / 9in Celsius umrechnen.Main.java: Bringen Sie alles zusammen! Sie erhalten eine Eingabe: einen Temperaturmesswert in Fahrenheit (double).Erstellen Sie einen
FahrenheitSensormit dem Eingabewert. Erstellen Sie dann einenSensorAdapter, der diesen Sensor kapselt. Speichern Sie den Adapter in einerTemperatureProvider-Variable, um zu demonstrieren, dass Ihre Wetteranwendung ihn über das erwartete Interface nutzen kann.Geben Sie das Ergebnis in diesem Format aus:
Temperature: [celsius] Cwobei 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 CBeachten 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!
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
}
}
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 this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem9Generics
Einführung in GenericsGenerische KlassenGenerische MethodenEingeschränkte TypparameterWildcards (?, extends, super)Zusammenfassung – Generische Container12Entwurfsmuster Teil 2
Command-MusterAdapter-MusterDecorator-MusterTemplate-Method-MusterState-MusterComposite-MusterIterator-Muster