Was sind Mixins
Ein Mixin ist ein Verfahren zur Code-Wiederverwendung. Es erlaubt Code über unabhängige Klassenvererbungsbäume hinweg gemeinsam zu nutzen. Das Ziel ist, mehreren Klassen auf einen Schlag Mitgliederimplementierungen zur Verfügung zu stellen. Es erinnert an Mehrfachvererbung, aber der eigentliche Zweck ist, einer Klasse verschiedene modulare Funktionen hinzuzufügen.
Mixin verwenden
Nutze das Schlüsselwort with, gefolgt von einem oder mehreren Mixin-Namen.
class Musician extends Performer with Musical {
// Code
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
Code-Sprache: Dart (dart)
Mixin definieren
Deklariere mit dem Schlüsselwort mixin.
Hinweis:
mixin class(ab Dart 3.0+) kann sowohl als normale Klasse als auch als Mixin eingesetzt werden.
Zwingende Einschränkungen
- In
mixin/mixin classdarf keinextendsgeschrieben werden - Es dürfen keine generativen Konstruktoren deklariert werden
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
class Musician with Musical {}
void main() {
var m = Musician();
m.canConduct = true;
m.entertainMe(); // Waving hands
}
Code-Sprache: Dart (dart)
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playingCode-Sprache: CSS (css)
Mixin muss externe Mitglieder aufrufen
Methoden / Eigenschaften, die das Mixin selbst nicht definiert
Ein Mixin benötigt oft Zugriff auf Mitglieder, die es nicht selbst implementiert. Hier werden vier gängige Standardlösungen vorgestellt.
Abstrakte Mitglieder im Mixin festlegen
Das Mixin deklariert eine abstrakte Methode. Jede Klasse, die dieses Mixin nutzt, muss diese abstrakte Methode implementieren.
mixin Musician {
// Abstrakte Methode, muss vom Nutzer implementiert werden
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
// Nutzer muss die Methode überschreiben und umsetzen
class Virtuoso with Musician {
@override
void playInstrument(String instrumentName) {
print('Plays the $instrumentName beautifully');
}
}
void main() {
var artist = Virtuoso();
artist.playPiano();
artist.playFlute();
}
Code-Sprache: Dart (dart)
Plays the Piano beautifully
Plays the Flute beautifully
Zugriff auf Zustand der Wirtsklasse per abstraktem Getter
Das Mixin definiert einen abstrakten Getter, um Felder der Wirtsklasse auszulesen und klassenübergreifend auf Zustände zuzugreifen.
/// Kann in jede Klasse mit name-Eigenschaft eingebunden werden, stellt automatisch == und hashCode auf Basis von name bereit
mixin NameIdentity {
String get name;
@override
int get hashCode => name.hashCode;
@override
bool operator ==(Object other) =>
other is NameIdentity && name == other.name;
}
class Person with NameIdentity {
final String name;
Person(this.name);
}
void main() {
var p1 = Person("Alice");
var p2 = Person("Alice");
var p3 = Person("Bob");
print(p1 == p2); // true
print(p1 == p3); // false
}
Code-Sprache: JavaScript (javascript)
Mixin implementiert Schnittstelle mit implements
Mit implements beschränkt das Mixin eine Schnittstelle und zwingt die einbindende Klasse, alle Methoden der Schnittstelle zu vervollständigen.
abstract interface class Tuner {
void tuneInstrument();
}
mixin Guitarist implements Tuner {
void playSong() {
tuneInstrument();
print('Strums guitar majestically.');
}
}
class PunkRocker with Guitarist {
@override
void tuneInstrument() {
print("Don't bother, being out of tune is punk rock.");
}
}
void main() {
PunkRocker().playSong();
}
Code-Sprache: JavaScript (javascript)
Don't bother, being out of tune is punk rock.
Strums guitar majestically.
on-Klausel: Mixin nur für Unterklassen eines bestimmten Typs zulassen
Funktion von on: Nur Klassen, die von dem festgelegten Typ erben, dürfen dieses Mixin einbinden.
Zusätzlich kann das Mixin innerhalb auf Mitglieder der Elternklasse zugreifen und super.xxx() aufrufen.
Nutze
onnur, wenn du im Mixin mitsuperElternmethoden aufrufen möchtest!
class Musician {
void musicianMethod() {
print('Playing music!');
}
}
// Darf nur in Unterklassen von Musician eingebunden werden
mixin MusicalPerformer on Musician {
void performerMethod() {
print('Performing music!');
super.musicianMethod(); // Aufruf der durch on begrenzten Elternmethode möglich
}
}
// SingerDancer erbt von Musician, also kann MusicalPerformer eingebunden werden
class SingerDancer extends Musician with MusicalPerformer {}
void main() {
SingerDancer().performerMethod();
}
Code-Sprache: Dart (dart)
Performing music!
Playing music!
SingerDancer bindet MusicalPerformer ein und kann daher dessen Methode performerMethod nutzen.
Ein Mixin funktioniert grob gesagt so: Eine Klasse holt sich alle Methoden aus einem anderen Mixin und kann diese anschließend verwenden.
⚠️ Falsches Beispiel:
Wenn eine Klasse nicht von
Musicianerbt und direktwith MusicalPerformerschreibt, kommt es zu einem Kompilierfehler.
Unterschiede zwischen class /mixin/mixin class
mixin: Nur mitwithnutzbar, keine Vererbung viaextendsclass: Kann mitextendsvererbt werden, nicht direkt als Mixin verwendbarmixin class:- kann mit
withals Mixin verwendet werden - kann zusätzlich mit
extendsals normale Elternklasse dienen
- kann mit
Gleiche Einschränkungen gelten:
- In mixin / mixin class kein extends, with schreiben
- In class / mixin class kein on schreiben
mixin class Musician { void play() { print("Musician is playing"); } } // Als Mixin verwenden class Novice1 with Musician {} // Als normale Elternklasse vererben class Novice2 extends Musician {} void main() { Novice1().play(); Novice2().play(); }Code-Sprache: Dart (dart)Ausgabeergebnis
D:\dartdemo\firstdart>dart run Building package executable... Built firstdart:firstdart. Musician is playing Musician is playingCode-Sprache: CSS (css)Mixins
Next: Aufzählungen