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.mp4Das 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.
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: " + 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 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!
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.mp4Wann 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
}
}
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