¿Qué son los Mixins?
Un Mixin es una forma de reutilizar código. Permite compartir lógica entre clases que no forman parte de la misma jerarquía de herencia, con el propósito de dotar a múltiples clases de implementaciones de miembros. Se asemeja un poco a la herencia múltiple, pero su objetivo es añadir funcionalidades modulares a una clase.
Uso de Mixin
Se emplea la palabra clave with, seguida de uno o varios nombres de Mixin.
class Musician extends Performer with Musical {
// Código
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
Lenguaje del código: Dart (dart)
Definir un Mixin
Se declara mediante la palabra reservada mixin.
Anotación:
mixin class(Dart 3.0+) se puede usar tanto como clase normal como Mixin.
Restricciones obligatorias
mixin/mixin classno admite el uso deextends- No se pueden declarar constructores generativos
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
}
Lenguaje del código: Dart (dart)
Resultado de ejecución
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playingLenguaje del código: CSS (css)
Mixin que requiere acceder a miembros externos
Métodos o propiedades que el propio Mixin no define
Frecuentemente, un Mixin necesita invocar miembros cuya implementación no posee. A continuación se exponen cuatro soluciones estándar.
Declarar miembros abstractos dentro del Mixin
El Mixin declara métodos abstractos, y toda clase que utilice este Mixin debe implementarlos.
mixin Musician {
// Método abstracto que debe implementar quien lo use
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
// El usuario debe sobrescribir e implementar
class Virtuoso with Musician {
@override
void playInstrument(String instrumentName) {
print('Plays the $instrumentName beautifully');
}
}
void main() {
var artist = Virtuoso();
artist.playPiano();
artist.playFlute();
}
Lenguaje del código: Dart (dart)
Plays the Piano beautifully
Plays the Flute beautifully
Acceder al estado de la clase huésped mediante getters abstractos
El Mixin define un getter abstracto para leer campos de la clase huésped y acceder al estado entre distintas clases.
/// Se puede mezclar en cualquier clase que cuente con propiedad name; proporciona automáticamente == y hashCode basados en name
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
}
Lenguaje del código: JavaScript (javascript)
Mixin que implementa interfaces con implements
Mediante implements, el Mixin establece restricciones de interfaz, obligando a la clase mezclada a definir todos los métodos de la interfaz.
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();
}
Lenguaje del código: JavaScript (javascript)
Don't bother, being out of tune is punk rock.
Strums guitar majestically.
Cláusula on: limitar qué clases pueden emplear el Mixin
Función de on: solo las clases derivadas del tipo especificado podrán incorporar este Mixin.
Además, dentro del Mixin se pueden invocar miembros de la clase padre y llamar a super.xxx().
¡Usa
onúnicamente si necesitas llamar métodos del padre consuperdesde el Mixin!
class Musician {
void musicianMethod() {
print('Playing music!');
}
}
// Solo se puede mezclar en subclases de Musician
mixin MusicalPerformer on Musician {
void performerMethod() {
print('Performing music!');
super.musicianMethod(); // Permite llamar métodos de la clase padre definida en on
}
}
// SingerDancer hereda de Musician, por lo tanto puede usar MusicalPerformer
class SingerDancer extends Musician with MusicalPerformer {}
void main() {
SingerDancer().performerMethod();
}
Lenguaje del código: Dart (dart)
Performing music!
Playing music!
SingerDancer incorpora MusicalPerformer, por lo que puede usar su método performerMethod
La mezcla funciona así: una clase puede tomar los métodos de otro Mixin para usarlos directamente.
⚠️ Ejemplo incorrecto:
Si una clase no hereda de
Musiciany usa directamentewith MusicalPerformer, se producirá un error de compilación.
Diferencias entre class / mixin / mixin class
mixin: solo se usa mediantewith, no se puede heredar conextendsclass: admiteextends, no se puede emplear directamente como mixinmixin class:- se puede usar como Mixin con
with - también puede funcionar como clase padre normal mediante
extends
- se puede usar como Mixin con
También se aplican las restricciones:
- mixin / mixin class no permiten extends ni with
- class / mixin class no admiten on
mixin class Musician { void play() { print("Musician is playing"); } } // Uso como Mixin class Novice1 with Musician {} // Uso como clase padre común class Novice2 extends Musician {} void main() { Novice1().play(); Novice2().play(); }Lenguaje del código: Dart (dart)Resultado de ejecución
D:\dartdemo\firstdart>dart run Building package executable... Built firstdart:firstdart. Musician is playing Musician is playingLenguaje del código: CSS (css)Mixins
Next: Enumeraciones