Polymorphismus über Interfaces
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 58 von 110.
In der vorherigen Lektion haben Sie Polymorphismus durch Vererbung kennengelernt – die Verwendung eines Basisklassentyps, um mit Kindobjekten zu arbeiten. Aber Polymorphismus funktioniert auch über Schnittstellen, und dieser Ansatz ist oft flexibler.
Wenn Klassen dieselbe Schnittstelle implementieren, kannst du sie polymorph behandeln, auch wenn sie keine Vererbungsbeziehung haben:
abstract class Printable {
void printDetails();
}
class Invoice implements Printable {
@override
void printDetails() => print('Invoice #1234');
}
class Report implements Printable {
@override
void printDetails() => print('Monthly Report');
}
class Receipt implements Printable {
@override
void printDetails() => print('Receipt for purchase');
}
void printAll(List<Printable> items) {
for (var item in items) {
item.printDetails();
}
}
void main() {
var documents = [Invoice(), Report(), Receipt()];
printAll(documents);
}Invoice, Report und Receipt sind völlig voneinander unabhängige Klassen – sie teilen keine gemeinsame Elternklasse. Da sie jedoch alle Printable implementieren, können wir sie in derselben Liste speichern und für jede einzelne printDetails() aufrufen.
Das ist leistungsstark, weil du damit Verhaltensverträge definieren kannst, ohne eine Vererbungshierarchie zu erzwingen. Jede Klasse kann ein Interface implementieren, unabhängig davon, wovon sie erbt. Dein Code wird modularer, da du neue druckbare Typen hinzufügen kannst, ohne bestehenden Code zu ändern – implementiere einfach das Interface.
Aufgabe
EinfachErstellen wir ein Mediaplayer-System, das Polymorphie durch Schnittstellen demonstriert. Du erstellst eine Schnittstelle, die definiert, was es bedeutet, „abspielbar“ zu sein, und implementierst dann mehrere unabhängige Medientypen, die diesen Vertrag erfüllen – dadurch können sie einheitlich verarbeitet werden, obwohl sie keine Vererbungsbeziehung haben.
Du organisierst deinen Code in zwei Dateien:
media.dart: Definiere hier deine Schnittstelle und Medienklassen:- Eine abstrakte Klasse
Playablemit zwei abstrakten Methoden:play()undString getMediaType() - Eine Klasse
Song, diePlayableimplementiert. Sie sollte überString titleundString artistverfügen. Ihre Methodeplay()gibtPlaying song: [title] by [artist]aus, undgetMediaType()gibt'Audio'zurück - Eine Klasse
Video, diePlayableimplementiert. Sie sollte überString titleundint duration(in Minuten) verfügen. Ihre Methodeplay()gibtPlaying video: [title] ([duration] min)aus, undgetMediaType()gibt'Video'zurück - Eine Klasse
Podcast, diePlayableimplementiert. Sie sollte überString titleundint episodeverfügen. Ihre Methodeplay()gibtPlaying podcast: [title] - Episode [episode]aus, undgetMediaType()gibt'Podcast'zurück
playAll(List<Playable> playlist), die die Liste durchläuft und für jedes Element[Media Type]:ausgibt, gefolgt vom Aufruf vonplay()für dieses Element.- Eine abstrakte Klasse
main.dart: Importiere deine Mediendatei und demonstriere die schnittstellenbasierte Polymorphie:- Erstelle eine
List<Playable>, die einenSongmit dem Titel'Imagine'und dem Interpreten'John Lennon', einVideomit dem Titel'Dart Tutorial'und der Dauer15sowie einenPodcastmit dem Titel'Tech Talk'und der Episodennummer42enthält - Übergib diese Liste an
playAll()
- Erstelle eine
Beachte, dass Song, Video und Podcast keine gemeinsame übergeordnete Klasse haben – es handelt sich um vollständig unabhängige Typen. Da sie jedoch alle Playable implementieren, kannst du sie in derselben Liste speichern und über die Schnittstelle einheitlich behandeln.
Erwartete Ausgabe:
Audio:
Playing song: Imagine by John Lennon
Video:
Playing video: Dart Tutorial (15 min)
Podcast:
Playing podcast: Tech Talk - Episode 42Probier es selbst
import 'media.dart';
void main() {
// TODO: Erstelle eine List<Playable>, die Folgendes enthält:
// - Einen Song mit dem Titel 'Imagine' und dem Künstler 'John Lennon'
// - Ein Video mit dem Titel 'Dart Tutorial' und der Dauer 15
// - Einen Podcast mit dem Titel 'Tech Talk' und der Episode 42
// TODO: Übergib die Liste an playAll()
}
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 – ZahlungsprozessorÜbe selbstständig: Online-Dart-Compiler