Adapter-Muster
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 95 von 110.
Das Adaptermuster ermöglicht es inkompatiblen Schnittstellen, zusammenzuarbeiten. Es fungiert als Brücke zwischen zwei Klassen, die andernfalls nicht zusammenarbeiten könnten, indem es eine vorhandene Klasse mit einer neuen Schnittstelle umschließt, die Clients erwarten. Dies ist besonders nützlich, wenn du Bibliotheken von Drittanbietern oder Legacy-Code in deine Anwendung integrierst.
Stell dir vor, du hast ein System, das mit JSON-Daten arbeitet, aber du musst eine Komponente integrieren, die nur XML ausgibt. Anstatt eine der beiden Klassen zu ändern, erstellst du einen Adapter, der zwischen ihnen übersetzt:
// Bestehende Schnittstelle, die Ihr System erwartet
abstract class JsonData {
String getJson();
}
// Legacy-Klasse mit inkompatibler Schnittstelle
class XmlService {
String getXml() {
return '<data><name>John</name></data>';
}
}
// Adapter macht XmlService kompatibel mit JsonData
class XmlToJsonAdapter implements JsonData {
final XmlService _xmlService;
XmlToJsonAdapter(this._xmlService);
@override
String getJson() {
String xml = _xmlService.getXml();
// XML in JSON umwandeln (vereinfacht)
return '{"name": "John"}';
}
}
void main() {
var xmlService = XmlService();
var adapter = XmlToJsonAdapter(xmlService);
print(adapter.getJson()); // {"name": "John"}
}Der XmlToJsonAdapter kapselt den XmlService und implementiert die JsonData-Schnittstelle. Der Client-Code arbeitet mit der vertrauten JsonData-Schnittstelle, ohne zu wissen, dass die Daten ursprünglich aus einer XML-Quelle stammen. Der Adapter übernimmt die gesamte Übersetzung intern.
Verwende das Adapter-Muster, wenn du eine vorhandene Klasse verwenden möchtest, ihre Schnittstelle jedoch nicht deinen Anforderungen entspricht, oder wenn du eine wiederverwendbare Klasse erstellen musst, die mit Klassen mit inkompatiblen Schnittstellen zusammenarbeitet.
Aufgabe
EinfachErstellen wir ein Adapter-System für einen Mediaplayer! Stell dir vor, du hast ein modernes Audiosystem, das erwartet, dass alle Medienquellen Audio über eine Standardschnittstelle bereitstellen, aber du musst einen altmodischen Schallplattenspieler integrieren, der eine völlig andere Art der Klangerzeugung verwendet.
Du wirst zwei Dateien erstellen, um deine Implementierung des Adaptermusters zu organisieren:
media_adapter.dart: Diese Datei enthält deine Schnittstellen- und Adapterklassen. Definiere eine abstrakte KlasseAudioSource, die dein modernes System erwartet – sie sollte eine MethodeString playAudio()besitzen, die die Audioausgabe als String zurückgibt. Erstelle anschließend eine KlasseVinylPlayer, die die Legacy-Ausrüstung repräsentiert – sie verfügt über ein FeldtrackNameund eine MethodeString spinRecord(), die*crackle* Playing vinyl: [trackName] *crackle*zurückgibt. Erstelle schließlich einenVinylAdapter, derAudioSourceimplementiert und einenVinylPlayerkapselt. Die MethodeplayAudio()des Adapters sollte die MethodespinRecord()des Schallplattenspielers aufrufen und das Ergebnis zurückgeben – so werden die inkompatiblen Schnittstellen überbrückt.main.dart: Importiere deine Media-Adapter-Datei und demonstriere, wie der Adapter den alten Schallplattenspieler mit Code funktionieren lässt, der die moderne SchnittstelleAudioSourceerwartet. Erstelle einenVinylPlayermit dem TitelnamenBohemian Rhapsody. Erstelle anschließend einenVinylAdapter, der diesen Schallplattenspieler kapselt. Speichere den Adapter in einer Variablen vom TypAudioSource, um zu beweisen, dass er der erwarteten Schnittstelle entspricht. RufeplayAudio()für deine Audioquelle auf und gib das Ergebnis aus.
Das Schöne an diesem Muster ist, dass dein Hauptcode mit der standardmäßigen Schnittstelle AudioSource arbeitet – er muss nicht wissen, dass im Hintergrund tatsächlich ein alter Schallplattenspieler die Arbeit übernimmt!
Erwartete Ausgabe:
*crackle* Playing vinyl: Bohemian Rhapsody *crackle*Probier es selbst
import 'media_adapter.dart';
void main() {
// TODO: Erstelle einen VinylPlayer mit dem Tracknamen "Bohemian Rhapsody"
// TODO: Erstelle einen VinylAdapter, der den VinylPlayer umhüllt
// TODO: Speichere den Adapter in einer Variable vom Typ AudioSource
// TODO: Rufe playAudio() auf deiner AudioSource auf und gib das Ergebnis aus
}
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 DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenInstanzvariablenGrundlagen von KonstruktorenRückblick – Einfacher Taschenrechner4Null-Sicherheit
Einführung in die Null-SicherheitNullable vs. Non-NullableDie Operatoren ? und !Late-Schlüsselwort und Null-SicherheitNull-bewusste OperatorenNull-Sicherheit in KlassenRückblick – Benutzers профilsystem7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrere InterfacesZusammenfassung – Formrechner10Collections & Generics
Übersicht über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische EinschränkungenIterable & IteratorRückblick – Generischer Speicher13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungErweiterungsmethodenAufrufbare KlassenVersiegelte Klassen (Dart 3)Records (Dart 3)Muster & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
StandardkonstruktorBenannte KonstruktorenInitialisierungslistenKonstantenkonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenRückblick – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _-Präfix-KonventionBibliotheksweite SichtbarkeitTiefergehende Getter & SetterInformationsverbergungRückblick – Studierendendaten8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas Schlüsselwort „on“ in MixinsMixin vs. VererbungMixin vs. SchnittstelleRückblick – Tiersystem11Spezielle Methoden
toString()-ÜberschreibunghashCode- & ==-ÜberschreibungComparable-Schnittstellecall()-MethodenoSuchMethod-ÜberschreibungWiederholung – Benutzerdefinierte Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFabrikmusterBeobachtermusterStrategiemuster17Abschließende Herausforderungen
E-Learning-PlattformBankingsystemSpielcharaktersystemFahrzeugvermietung3Klassen-Eigenschaften
Instanz- vs. statische MemberFinal- und Const-FelderLate-VariablenStatische Methoden und FelderGetter und SetterRückblick – Bankkontoverwaltung6Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungDie Annotation @overrideDas Schlüsselwort final für KlassenKonstruktoren und VererbungZusammenfassung – Mitarbeiterhierarchie9Polymorphismus
Grundlagen des PolymorphismusPolymorphismus über InterfacesLaufzeit-TypüberprüfungDie Operatoren is & asCovariant-SchlüsselwortZusammenfassung – Zahlungsprozessor12Asynchrone OOP
Futures & async/awaitStream-GrundlagenStream-ControllerAsynchrone KonstruktorenAsync in KlassenmethodenZusammenfassung – Datenabruf15Entwurfsmuster Teil 2
Command-MusterAdapter-MusterDecorator-MusterTemplate-Method-MusterState-MusterComposite-MusterRepository-MusterÜbe selbstständig: Online-Dart-Compiler