Einführung in Mixins
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 50 von 110.
Sie haben gelernt, dass Dart nur das Erweitern einer Klasse erlaubt, und obwohl Sie mehrere Schnittstellen implementieren können, müssen Sie den gesamten Code selbst schreiben. Aber was ist, wenn Sie tatsächlichen Implementierungscode über mehrere nicht verwandte Klassen hinweg teilen möchten? Hier kommen Mixins ins Spiel.
Ein Mixin ist eine Möglichkeit, Code in mehreren Klassenhierarchien wiederzuverwenden. Stellen Sie es sich als ein Bündel von Methoden und Eigenschaften vor, das Sie in jede beliebige Klasse „hineinmischen“ können, um ihr neue Funktionen zu verleihen, ohne Vererbung zu nutzen.
mixin Swimming {
void swim() {
print('Swimming through the water');
}
}
class Duck with Swimming {
void quack() {
print('Quack!');
}
}
class Fish with Swimming {
void blowBubbles() {
print('Blub blub');
}
}
void main() {
var duck = Duck();
duck.quack();
duck.swim(); // Aus dem Mixin
var fish = Fish();
fish.swim(); // Gleiche Implementierung, andere Klasse
}Beachten Sie das Schlüsselwort with – so wenden Sie ein Mixin auf eine Klasse an. Im Gegensatz zu implements müssen Sie die Methode nicht selbst schreiben. Das Mixin stellt den eigentlichen Code bereit, und Ihre Klasse erhält diese Funktionalität automatisch.
Mixins lösen ein echtes Problem: Duck und Fish sind nicht durch Vererbung miteinander verwandt, dennoch benötigen beide ein Schwimmverhalten. Mit Mixins schreiben Sie den Code einmal und teilen ihn überall dort, wo er benötigt wird.
Aufgabe
EinfachLassen Sie uns ein Musikinstrumentensystem bauen, das demonstriert, wie Mixins es ermöglichen, Verhalten über nicht verwandte Klassen hinweg zu teilen. Sie werden ein Mixin erstellen, das eine Tuning-Funktionalität bereitstellt, und dieses dann auf verschiedene Instrumente anwenden, die nicht durch Vererbung miteinander verwandt sind.
Sie werden Ihren Code in zwei Dateien organisieren:
instruments.dart: Definieren Sie hier Ihr Mixin und Ihre Instrumentenklassen:- Ein
TunableMixin mit einer Methodetune(), dieTuning the instrument...ausgibt, und einer MethodecheckTuning(), dieTuning is perfect!ausgibt. - Eine
GuitarKlasse, die dasTunableMixin verwendet. Fügen Sie eineString brandEigenschaft mit einem Konstruktor hinzu. Fügen Sie eine Methodestrum()hinzu, die[brand] guitar strumming chordsausgibt. - Eine
PianoKlasse, die ebenfalls dasTunableMixin verwendet. Fügen Sie eineint keysEigenschaft mit einem Konstruktor hinzu. Fügen Sie eine Methodeplay()hinzu, diePlaying [keys]-key pianoausgibt.
- Ein
main.dart: Importieren Sie Ihre Instrumentendatei und demonstrieren Sie, wie beide nicht verwandten Instrumente Tuning-Fähigkeiten von demselben Mixin erhalten:- Erstellen Sie eine
Guitarmit der Marke'Fender'. - Erstellen Sie ein
Pianomit88Tasten. - Für die Gitarre: Rufen Sie
tune()auf, dannstrum(), danncheckTuning(). - Geben Sie eine Leerzeile aus.
- Für das Klavier: Rufen Sie
tune()auf, dannplay(), danncheckTuning().
- Erstellen Sie eine
Beachten Sie, dass Guitar und Piano völlig unterschiedliche Instrumente ohne Vererbungsbeziehung sind, aber beide genau dieselben Tuning-Methoden vom Tunable Mixin erhalten. Sie schreiben den Tuning-Code einmal, und beide Klassen können ihn mit dem Schlüsselwort with verwenden.
Erwartete Ausgabe:
Tuning the instrument...
Fender guitar strumming chords
Tuning is perfect!
Tuning the instrument...
Playing 88-key piano
Tuning is perfect!Spickzettel
Ein Mixin ist eine Möglichkeit, Code über mehrere nicht verwandte Klassen hinweg wiederzuverwenden, ohne Vererbung zu nutzen. Es ist ein Bündel von Methoden und Eigenschaften, die man in jede beliebige Klasse „hineinmischen“ kann.
Definieren Sie ein Mixin mit dem Schlüsselwort mixin:
mixin Swimming {
void swim() {
print('Swimming through the water');
}
}Wenden Sie ein Mixin auf eine Klasse an, indem Sie das Schlüsselwort with verwenden:
class Duck with Swimming {
void quack() {
print('Quack!');
}
}
class Fish with Swimming {
void blowBubbles() {
print('Blub blub');
}
}Im Gegensatz zu implements müssen Sie die Methodenimplementierung nicht selbst schreiben – das Mixin liefert den tatsächlichen Code, und Ihre Klasse erhält diese Funktionalität automatisch.
Sowohl Duck als auch Fish können nun die Methode swim() verwenden, obwohl sie nicht durch Vererbung miteinander verwandt sind:
var duck = Duck();
duck.swim(); // From the mixin
var fish = Fish();
fish.swim(); // Same implementation, different classProbier es selbst
import 'instruments.dart';
void main() {
// TODO: Erstelle eine Gitarre mit der Marke 'Fender'
// TODO: Erstelle ein Klavier mit 88 Tasten
// TODO: Für die Gitarre: rufe tune() auf, dann strum(), dann checkTuning()
// TODO: Drucke eine Leerzeile
// TODO: Für das Klavier: rufe tune() auf, dann play(), dann checkTuning()
}
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 this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor