Menu
Coddy logo textTech

Mixin vs. Schnittstelle

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 55 von 110.

Sie haben gesehen, wie Mixins im Vergleich zur Vererbung abschneiden. Lassen Sie uns nun Mixins mit Interfaces vergleichen, da beide es ermöglichen, mit mehreren Typen zu arbeiten. Der entscheidende Unterschied liegt darin, was sie bieten: Interfaces definieren einen Vertrag, während Mixins eine Implementierung bereitstellen.

Wenn du ein Interface implementierst, versprichst du, bestimmte Methoden bereitzustellen, aber du schreibst den gesamten Code selbst. Wenn du ein Mixin verwendest, erhältst du den eigentlichen Code kostenlos.

// Interface-Ansatz - Sie müssen alles implementieren
abstract class Printable {
  void printInfo();
}

class Report implements Printable {
  @override
  void printInfo() {
    print('Printing report...');  // Das schreiben Sie
  }
}

// Mixin-Ansatz - Implementierung enthalten
mixin Printable {
  void printInfo() {
    print('Printing...');  // Bereits für Sie geschrieben
  }
}

class Report with Printable {}  // Erhält printInfo() automatisch

Wann solltest du also welches verwenden? Verwende ein Interface, wenn verschiedene Klassen dieselben Methodensignaturen, aber unterschiedliche Implementierungen benötigen. Verwende ein Mixin, wenn Klassen dasselbe Verhalten teilen sollen.

FunktionSchnittstelleMixin
BietetNur VertragVertrag + Code
ImplementierungDu schreibst sieEnthalten
Schlüsselwortimplementswith
Am besten geeignet fürUnterschiedliche Verhaltensweisen, gleiche APIGemeinsames Verhalten

Sie können sogar beide Ansätze kombinieren – verwenden Sie Interfaces, um zu definieren, was eine Klasse tun kann, und Mixins, um bei Bedarf gängige Implementierungen bereitzustellen. In Dart müssen Sie beim Kombinieren von beidem with immer vor implements setzen:

class MyClass with SomeMixin implements SomeInterface {
  // with steht vor implements
}
challenge icon

Aufgabe

Einfach

Erstellen wir ein Benachrichtigungssystem, das zeigt, wann Schnittstellen und wann Mixins verwendet werden sollten. Du erstellst eine Schnittstelle für Benachrichtigungen, die unterschiedliche Implementierungen benötigen, und ein Mixin für gemeinsames Protokollierungsverhalten, das bei allen Benachrichtigungstypen identisch sein sollte.

Du organisierst deinen Code in drei Dateien:

  • notifiable.dart: Definiere eine abstrakte Klasse Notifiable, die als Schnittstelle dient. Sie sollte zwei abstrakte Methoden deklarieren: send(String message) und getChannel(), die einen String zurückgibt. Verschiedene Benachrichtigungstypen implementieren diese Methoden je nach ihrem spezifischen Kanal unterschiedlich.
  • logging.dart: Erstelle ein Logging-Mixin, das gemeinsames Verhalten bereitstellt, das alle Benachrichtigungen haben sollten. Füge eine Methode logSent(String channel, String message) hinzu, die [LOG] Sent via [channel]: [message] ausgibt, sowie eine Methode logTimestamp(), die [LOG] Timestamp recorded ausgibt. Dieses Verhalten ist für alle Benachrichtigungstypen identisch und eignet sich daher perfekt für ein Mixin.
  • main.dart: Importiere beide Dateien und erstelle zwei Benachrichtigungsklassen, die die Schnittstelle mit dem Mixin kombinieren:
    • Eine Klasse EmailNotification, die das Logging-Mixin verwendet und Notifiable implementiert. Ihr getChannel() sollte 'Email' zurückgeben, und ihre send()-Methode sollte Sending email: [message] ausgeben, anschließend logSent() mit dem Kanal und der Nachricht aufrufen und danach logTimestamp() aufrufen.
    • Eine Klasse SMSNotification, die das Logging-Mixin verwendet und Notifiable implementiert. Ihr getChannel() sollte 'SMS' zurückgeben, und ihre send()-Methode sollte Sending SMS: [message] ausgeben, anschließend logSent() mit dem Kanal und der Nachricht aufrufen und danach logTimestamp() aufrufen.
    Erstelle anschließend ein EmailNotification und rufe send('Hello World') auf, gib eine leere Zeile aus, erstelle ein SMSNotification und rufe send('Quick update') auf.

Beachte, wie die Schnittstelle jede Klasse dazu zwingt, ihre eigenen Implementierungen von send() und getChannel() zu schreiben (unterschiedliches Verhalten), während das Mixin die Protokollierungsmethoden bereitstellt, die für beide identisch funktionieren (gemeinsames Verhalten).

Erwartete Ausgabe:

Sending email: Hello World
[LOG] Sent via Email: Hello World
[LOG] Timestamp recorded

Sending SMS: Quick update
[LOG] Sent via SMS: Quick update
[LOG] Timestamp recorded

Probier es selbst

import 'notifiable.dart';
import 'logging.dart';

// TODO: Erstelle die Klasse EmailNotification, die:
//       - das Logging Mixin verwendet (with)
//       - Notifiable implementiert (implements)
//       - getChannel() gibt 'Email' zurück
//       - send() gibt 'Sending email: [message]' aus, ruft dann logSent() und danach logTimestamp() auf

// TODO: Erstelle die Klasse SMSNotification, die:
//       - das Logging Mixin verwendet (with)
//       - Notifiable implementiert (implements)
//       - getChannel() gibt 'SMS' zurück
//       - send() gibt 'Sending SMS: [message]' aus, ruft dann logSent() und danach logTimestamp() auf

void main() {
  // TODO: Erstelle eine EmailNotification und rufe send('Hello World') auf
  
  // TODO: Gib eine Leerzeile aus
  
  // TODO: Erstelle eine SMSNotification und rufe send('Quick update') auf
}
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

Übe selbstständig: Online-Dart-Compiler