Qu’est-ce qu’un Mixin
Le Mixin est une méthode de réutilisation du code. Il permet de partager du code entre des hiérarchies de classes sans lien d’héritage direct. Son objectif est d’ajouter collectivement des implémentations de membres à plusieurs classes. Il ressemble un peu à l’héritage multiple, mais son but principal est d’apporter des fonctionnalités modulaires à une classe.
Utiliser un Mixin
On utilise le mot-clé with, suivi d’un ou plusieurs noms de Mixin.
class Musician extends Performer with Musical {
// code
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
Langage du code : Dart (dart)
Définir un Mixin
On le déclare avec le mot-clé mixin.
Complément :
mixin class(Dart 3.0+) peut fonctionner à la fois comme une classe classique et comme un Mixin.
Contraintes obligatoires
- Dans un
mixin/mixin class, il est interdit d’écrireextends - Impossible de déclarer des constructeurs générateurs (generative constructor)
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
}
Langage du code : Dart (dart)
Résultat d’exécution
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playingLangage du code : CSS (css)
Mixin ayant besoin d’appeler des membres externes
Méthodes / propriétés non définies au sein du Mixin
Un Mixin doit souvent appeler des membres qu’il n’implémente pas lui-même. Voici quatre solutions standard.
Définir des membres abstraits dans le Mixin
Le Mixin déclare une méthode abstraite. Toute classe utilisant ce Mixin doit implémenter cette méthode abstraite.
mixin Musician {
// Méthode abstraite, à implémenter par l’utilisateur
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
// L’utilisateur doit redéfinir et implémenter
class Virtuoso with Musician {
@override
void playInstrument(String instrumentName) {
print('Plays the $instrumentName beautifully');
}
}
void main() {
var artist = Virtuoso();
artist.playPiano();
artist.playFlute();
}
Langage du code : Dart (dart)
Plays the Piano beautifully
Plays the Flute beautifully
Accéder à l’état de la classe hôte via un Getter abstrait
Le Mixin définit un getter abstrait pour lire les champs de la classe hôte et accéder à l’état d’une autre classe.
/// Peut être mélangé à toute classe disposant d’une propriété name, fournit automatiquement == et hashCode basés sur 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
}
Langage du code : JavaScript (javascript)
Mixin qui implémente une interface avec implements
Avec implements, le Mixin contraint une interface et force la classe à intégrer toutes les méthodes de cette interface.
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();
}
Langage du code : JavaScript (javascript)
Don't bother, being out of tune is punk rock.
Strums guitar majestically.
Clause on : restreindre le Mixin aux sous-classes d’un type précis
Rôle de on : seules les classes héritant du type spécifié peuvent utiliser ce Mixin.
De plus, au sein du Mixin, on peut appeler les membres de la classe parente et utiliser super.xxx().
N’utilisez
onque si vous devez appeler des méthodes parentes avecsuperdans le Mixin !
class Musician {
void musicianMethod() {
print('Playing music!');
}
}
// Ne peut être mélangé qu’aux sous-classes de Musician
mixin MusicalPerformer on Musician {
void performerMethod() {
print('Performing music!');
super.musicianMethod(); // Appel possible des méthodes parentes limitées par on
}
}
// SingerDancer hérite de Musician, il peut donc utiliser MusicalPerformer
class SingerDancer extends Musician with MusicalPerformer {}
void main() {
SingerDancer().performerMethod();
}
Langage du code : Dart (dart)
Performing music!
Playing music!
SingerDancer utilise MusicalPerformer, il peut donc accéder à la méthode performerMethod qui s’y trouve.
Concrètement, le mélange permet à une classe de récupérer les méthodes d’un Mixin pour les utiliser comme si elles lui appartenaient.
⚠️ Exemple erroné :
Si une classe n’hérite pas de
Musician, écrire directementwith MusicalPerformerprovoque une erreur de compilation.
Différences entre class /mixin/mixin class
mixin: utilisable uniquement viawith, impossible à hériter parextendsclass: peut être héritée avecextends, ne peut pas servir directement de mixinmixin class:- peut servir de Mixin via
with - peut aussi être héritée normalement avec
extends
- peut servir de Mixin via
Mêmes contraintes applicables :
- Dans mixin / mixin class, pas d’écriture de extends, with
- Dans class / mixin class, pas d’écriture de on
mixin class Musician { void play() { print("Musician is playing"); } } // Utilisé comme Mixin class Novice1 with Musician {} // Utilisé comme classe parente classique class Novice2 extends Musician {} void main() { Novice1().play(); Novice2().play(); }Langage du code : Dart (dart)Résultat d’exécution
D:\dartdemo\firstdart>dart run Building package executable... Built firstdart:firstdart. Musician is playing Musician is playingLangage du code : CSS (css)Mixins
Next: Énumérations