Menu
Coddy logo textTech

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 dasselbe Interface implementieren, können Sie diese polymorph behandeln, selbst 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 sich keine gemeinsame Elternklasse. Da sie jedoch alle Printable implementieren, können wir sie in derselben Liste speichern und für jedes Objekt printDetails() aufrufen.

Dies ist leistungsstark, da es Ihnen ermöglicht, Verhaltensverträge zu definieren, ohne eine Vererbungshierarchie zu erzwingen. Jede Klasse kann ein Interface implementieren, unabhängig davon, was sie erweitert. Ihr Code wird modularer, da Sie neue druckbare Typen hinzufügen können, ohne bestehenden Code zu ändern – implementieren Sie einfach das Interface.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Media-Player-System bauen, das Polymorphismus durch Schnittstellen demonstriert. Sie werden ein Interface erstellen, das definiert, was es bedeutet, "abspielbar" zu sein, und dann mehrere nicht verwandte Medientypen implementieren, die alle diesen Vertrag erfüllen – was es ermöglicht, sie einheitlich zu behandeln, obwohl sie keine Vererbungsbeziehung haben.

Sie werden Ihren Code in zwei Dateien organisieren:

  • media.dart: Definieren Sie hier Ihr Interface und Ihre Medienklassen:
    • Eine abstrakte Klasse Playable mit zwei abstrakten Methoden: play() und String getMediaType()
    • Eine Klasse Song, die Playable implementiert. Sie sollte einen String title und einen String artist haben. Ihre play()-Methode gibt Playing song: [title] by [artist] aus und getMediaType() gibt 'Audio' zurück
    • Eine Klasse Video, die Playable implementiert. Sie sollte einen String title und ein int duration (in Minuten) haben. Ihre play()-Methode gibt Playing video: [title] ([duration] min) aus und getMediaType() gibt 'Video' zurück
    • Eine Klasse Podcast, die Playable implementiert. Sie sollte einen String title und ein int episode haben. Ihre play()-Methode gibt Playing podcast: [title] - Episode [episode] aus und getMediaType() gibt 'Podcast' zurück
    Erstellen Sie außerdem eine Funktion playAll(List<Playable> playlist), die durch die Liste iteriert und für jedes Element [Media Type]: ausgibt, gefolgt vom Aufruf von play() für dieses Element.
  • main.dart: Importieren Sie Ihre Mediendatei und demonstrieren Sie schnittstellenbasierten Polymorphismus:
    • Erstellen Sie eine List<Playable>, die einen Song mit dem Titel 'Imagine' und dem Künstler 'John Lennon', ein Video mit dem Titel 'Dart Tutorial' und der Dauer 15 sowie einen Podcast mit dem Titel 'Tech Talk' und der Episode 42 enthält
    • Übergeben Sie diese Liste an playAll()

Beachten Sie, dass Song, Video und Podcast keine gemeinsame Elternklasse haben – es sind völlig unverbundene Typen. Da sie jedoch alle Playable implementieren, können Sie sie in derselben Liste speichern und sie über das Interface einheitlich behandeln.

Erwartete Ausgabe:

Audio:
Playing song: Imagine by John Lennon
Video:
Playing video: Dart Tutorial (15 min)
Podcast:
Playing podcast: Tech Talk - Episode 42

Spickzettel

Polymorphismus funktioniert über Schnittstellen (Interfaces) und ermöglicht es, nicht verwandte Klassen einheitlich zu behandeln, ohne dass Vererbungsbeziehungen bestehen müssen.

Klassen, die dieselbe Schnittstelle implementieren, können polymorph verwendet werden:

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');
}

void printAll(List<Printable> items) {
  for (var item in items) {
    item.printDetails();
  }
}

void main() {
  var documents = [Invoice(), Report()];
  printAll(documents);
}

Interface-basierter Polymorphismus ermöglicht es Ihnen:

  • Verhaltensverträge zu definieren, ohne Vererbungshierarchien zu erzwingen
  • Nicht verwandte Typen in derselben Sammlung zu speichern
  • Neue Typen hinzuzufügen, ohne bestehenden Code zu ändern
  • Code modularer und flexibler zu gestalten

Probier 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()
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung