Introducción a los Mixins
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 50 de 110.
Has aprendido que Dart solo permite extender una clase y, aunque puedes implementar múltiples interfaces, debes escribir todo el código tú mismo. ¿Pero qué pasa si quieres compartir código de implementación real entre múltiples clases no relacionadas? Aquí es donde entran los mixins.
Un mixin es una forma de reutilizar código en múltiples jerarquías de clases. Piénsalo como un conjunto de métodos y propiedades que puedes "mezclar" en cualquier clase, otorgándole nuevas capacidades sin utilizar la herencia.
mixin Swimming {
void swim() {
print('Swimming through the water');
}
}
class Duck with Swimming {
void quack() {
print('Quack!');
}
}
class Fish with Swimming {
void blowBubbles() {
print('Blub blub');
}
}
void main() {
var duck = Duck();
duck.quack();
duck.swim(); // Desde el mixin
var fish = Fish();
fish.swim(); // Misma implementación, diferente clase
}Observa la palabra clave with: así es como aplicas un mixin a una clase. A diferencia de implements, no necesitas escribir el método tú mismo. El mixin proporciona el código real y tu clase obtiene esa funcionalidad automáticamente.
Los mixins resuelven un problema real: Duck y Fish no están relacionados mediante herencia, pero ambos necesitan el comportamiento de nadar. Con los mixins, escribes el código una vez y lo compartes donde sea necesario.
Desafío
FácilVamos a construir un sistema de instrumentos musicales que demuestre cómo los mixins permiten compartir comportamientos entre clases no relacionadas. Crearás un mixin que proporcione funcionalidad de afinación y luego lo aplicarás a diferentes instrumentos que no están relacionados mediante herencia.
Organizarás tu código en dos archivos:
instruments.dart: Define aquí tu mixin y las clases de instrumentos:- Un mixin
Tunablecon un métodotune()que imprimaTuning the instrument...y un métodocheckTuning()que imprimaTuning is perfect! - Una clase
Guitarque use el mixinTunable. Añade una propiedadString brandcon un constructor. Incluye un métodostrum()que imprima[brand] guitar strumming chords - Una clase
Pianoque también use el mixinTunable. Añade una propiedadint keyscon un constructor. Incluye un métodoplay()que imprimaPlaying [keys]-key piano
- Un mixin
main.dart: Importa tu archivo de instrumentos y demuestra cómo ambos instrumentos no relacionados obtienen capacidades de afinación del mismo mixin:- Crea una
Guitarcon la marca'Fender' - Crea un
Pianocon88teclas - Para la guitarra: llama a
tune(), luego astrum(), y después acheckTuning() - Imprime una línea vacía
- Para el piano: llama a
tune(), luego aplay(), y después acheckTuning()
- Crea una
Observa cómo Guitar y Piano son instrumentos completamente diferentes sin relación de herencia, y aun así ambos obtienen exactamente los mismos métodos de afinación del mixin Tunable. Escribes el código de afinación una vez, y ambas clases pueden usarlo con la palabra clave with.
Salida esperada:
Tuning the instrument...
Fender guitar strumming chords
Tuning is perfect!
Tuning the instrument...
Playing 88-key piano
Tuning is perfect!Hoja de referencia
Un mixin es una forma de reutilizar código en múltiples clases no relacionadas sin utilizar la herencia. Es un conjunto de métodos y propiedades que puedes "mezclar" (mix into) en cualquier clase.
Define un mixin utilizando la palabra clave mixin:
mixin Swimming {
void swim() {
print('Swimming through the water');
}
}Aplica un mixin a una clase utilizando la palabra clave with:
class Duck with Swimming {
void quack() {
print('Quack!');
}
}
class Fish with Swimming {
void blowBubbles() {
print('Blub blub');
}
}A diferencia de implements, no necesitas escribir la implementación del método tú mismo: el mixin proporciona el código real y tu clase adquiere esa funcionalidad automáticamente.
Tanto Duck como Fish pueden ahora usar el método swim() aunque no estén relacionados a través de la herencia:
var duck = Duck();
duck.swim(); // From the mixin
var fish = Fish();
fish.swim(); // Same implementation, different classPruébalo tú mismo
import 'instruments.dart';
void main() {
// TODO: Crear una Guitarra con la marca 'Fender'
// TODO: Crear un Piano con 88 teclas
// TODO: Para la guitarra: llamar a tune(), luego strum(), luego checkTuning()
// TODO: Imprimir una línea vacía
// TODO: Para el piano: llamar a tune(), luego play(), luego checkTuning()
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository