# Mixins en Dart
Los Mixins son una forma de reutilizar código de una clase en múltiples jerarquías de clases. Permiten "inyectar" funcionalidad en una clase sin usar herencia tradicional.
## ¿Por qué Mixins?
Dart solo soporta herencia simple (`extends`). Si quieres compartir código entre clases que no comparten una jerarquía directa, los Mixins son la solución.
## Sintaxis Básica
Se definen con `mixin` y se usan con `with`.
```dart
mixin Musical {
bool canPlay = true;
void playInstrument() {
print('Playing music 🎵');
}
}
mixin Aggressive {
void attack() {
print('Attacking! ⚔️');
}
}
class Performer with Musical {
// Tiene acceso a playInstrument()
}
class Warrior with Aggressive {
// Tiene acceso a attack()
}
// Composición de múltiples mixins
class Bard extends Performer with Aggressive {
// Tiene acceso a playInstrument() Y attack()
void performBattleSong() {
playInstrument();
attack();
}
}
```
## Restricciones de Mixins (`on`)
Puedes restringir un mixin para que solo pueda ser usado por clases que extiendan de cierta clase base. Esto te permite acceder a métodos de esa clase base dentro del mixin (usando `super`).
```dart
abstract class Animal {
void move();
}
// Este mixin SOLO se puede usar en subclases de Animal
mixin FastMovement on Animal {
void runFast() {
// Podemos llamar a move() porque sabemos que 'this' es un Animal
print('Running fast!');
move();
}
}
class Cheetah extends Animal with FastMovement {
@override
void move() => print('Cheetah moving');
}
// ❌ Error: Car no es un Animal
// class Car with FastMovement {}
```
## Mixins en Flutter: `SingleTickerProviderStateMixin`
El uso más común en Flutter es para animaciones.
```dart
class MyAnimatedWidget extends StatefulWidget {
@override
_MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();
}
// El mixin agrega la capacidad de proveer un Ticker
class _MyAnimatedWidgetState extends State
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
// 'vsync: this' funciona gracias al mixin
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 1),
);
}
}
```
## Mixins vs Herencia vs Interfaces
| Característica | Herencia (`extends`) | Interfaz (`implements`) | Mixin (`with`) |
|----------------|----------------------|-------------------------|----------------|
| Propósito | Jerarquía "Es un" | Contrato de API | Capacidades "Tiene un" |
| Reutilización código | ✅ Sí | ❌ No | ✅ Sí |
| Múltiple | ❌ No | ✅ Sí | ✅ Sí |
| Estado | ✅ Sí | ❌ No | ✅ Sí |
## Caso de Uso Real: Logging Mixin
```dart
mixin LoggerMixin {
void log(String message) {
final timestamp = DateTime.now().toIso8601String();
print('[$timestamp] [${this.runtimeType}]: $message');
}
void logError(String error) {
print('🔴 ERROR [${this.runtimeType}]: $error');
}
}
class UserRepository with LoggerMixin {
void getUser(String id) {
log('Fetching user $id');
try {
// ...
} catch (e) {
logError(e.toString());
}
}
}
class AuthBloc with LoggerMixin {
void login() {
log('Login attempt');
}
}
```
## Resolución de Conflictos
Si múltiples mixins tienen el mismo método, gana el **último** en la lista `with`.
```dart
mixin A {
void foo() => print('A');
}
mixin B {
void foo() => print('B');
}
class C with A, B {}
class D with B, A {}
void main() {
C().foo(); // Imprime 'B' (B es el último)
D().foo(); // Imprime 'A' (A es el último)
}
```
## Conclusión
Los Mixins son una herramienta poderosa para la composición de código en Dart. Úsalos para:
- Compartir utilidades (Logging, Validación).
- Agregar capacidades (Animation, Scroll).
- Evitar la herencia múltiple compleja.
- Mantener tus clases enfocadas y modulares.
Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.
Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.