O que são Mixins?
Um Mixin é uma forma de reutilizar código. Ele possibilita reaproveitar lógica em classes que não compartilham a mesma cadeia de herança, com o objetivo de implementar membros em várias classes em lote. Se assemelha um pouco à herança múltipla, mas sua finalidade é adicionar funcionalidades modulares a uma classe.
Utilizar um Mixin
Use a palavra-chave with, seguida de um ou mais nomes 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;
}
}
Code language: Dart (dart)
Declarar um Mixin
Declare utilizando a palavra reservada mixin.
Observação:
mixin class(Dart 3.0+) funciona tanto como uma classe comum quanto como um Mixin.
Regras obrigatórias
mixin/mixin classnão aceita o comandoextends- Não é possível declarar construtores gerativos
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 language: Dart (dart)
Resultado da execução
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playingCode language: CSS (css)
Mixin que precisa acessar membros externos
Métodos ou propriedades que o próprio Mixin não implementa
Muitas vezes um Mixin precisa chamar membros que ele não implementa. Veja quatro abordagens padrão abaixo.
Definir membros abstratos dentro do Mixin
O Mixin declara métodos abstratos, e toda classe que usar esse Mixin deve implementá-los.
mixin Musician {
// Método abstrato que deve ser implementado por quem usar
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
// A classe usuária precisa sobrescrever 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();
}
Code language: Dart (dart)
Plays the Piano beautifully
Plays the Flute beautifully
Acessar o estado da classe hospedeira via getter abstrato
O Mixin define um getter abstrato para ler campos da classe hospedeira, permitindo acessar estados entre classes diferentes.
/// Pode ser misturado em qualquer classe com propriedade name; fornece automaticamente == e hashCode baseados no nome
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 language: JavaScript (javascript)
Mixin implementando interface com implements
Usando implements, o Mixin define restrições de interface, obrigando a classe que o incorpora a implementar todos os métodos da 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();
}
Code language: JavaScript (javascript)
Don't bother, being out of tune is punk rock.
Strums guitar majestically.
Cláusula on: limitar quais classes podem usar o Mixin
Função do on: apenas classes derivadas do tipo informado conseguem incorporar esse Mixin.
Além disso, dentro do Mixin é possível acessar membros da classe base e chamar super.xxx().
Só use
onse precisar invocar métodos da classe pai comsuperdentro do Mixin!
class Musician {
void musicianMethod() {
print('Playing music!');
}
}
// Só pode ser usado por subclasses de Musician
mixin MusicalPerformer on Musician {
void performerMethod() {
print('Performing music!');
super.musicianMethod(); // Chama método da classe base definida no on
}
}
// SingerDancer herda de Musician, então pode usar MusicalPerformer
class SingerDancer extends Musician with MusicalPerformer {}
void main() {
SingerDancer().performerMethod();
}
Code language: Dart (dart)
Performing music!
Playing music!
A classe SingerDancer incorpora o MusicalPerformer e, por isso, consegue usar o método performerMethod
Funciona assim: uma classe importa os métodos de um Mixin para usá-los diretamente.
⚠️ Exemplo incorreto:
Se uma classe não herdar de
Musiciane tentar usarwith MusicalPerformer, ocorrerá erro de compilação.
Diferença entre class / mixin / mixin class
mixin: só pode ser usado comwith, não aceita herança viaextendsclass: aceitaextends, não pode ser usado diretamente como mixinmixin class:- funciona como Mixin usando
with - também pode ser classe base comum com
extends
- funciona como Mixin usando
As restrições também valem:
- mixin / mixin class não aceitam extends nem with
- class / mixin class não aceitam on
mixin class Musician { void play() { print("Musician is playing"); } } // Usado como Mixin class Novice1 with Musician {} // Usado como classe base comum class Novice2 extends Musician {} void main() { Novice1().play(); Novice2().play(); }Code language: Dart (dart)Resultado da execução
D:\dartdemo\firstdart>dart run Building package executable... Built firstdart:firstdart. Musician is playing Musician is playingCode language: CSS (css)Mixins
Next: Aufzählungen