Módulo 02: POO Avanzada en Dart

Mixins

Sistema Clases

# 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.