Palabra clave covariant
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 61 de 110.
Cuando sobrescribes un método en una subclase, Dart normalmente requiere que los tipos de parámetros coincidan exactamente. Pero a veces quieres que un método de una subclase acepte un tipo más específico que el padre. La palabra clave covariant permite esto.
Considera un escenario donde una clase Animal tiene un método que acepta otro Animal:
class Animal {
void chase(Animal other) {
print('Chasing an animal');
}
}
class Dog extends Animal {
@override
void chase(covariant Dog other) {
print('Dog chasing another dog');
}
}Sin covariant, Dart se quejaría de que Dog no es del mismo tipo que Animal. Al añadir covariant antes del parámetro, le dices a Dart: "Sé que esto es más específico y me aseguraré de que solo se pase el tipo correcto."
Esto es útil cuando las subclases lógicamente solo deberían trabajar con su propio tipo:
void main() {
Dog dog1 = Dog();
Dog dog2 = Dog();
dog1.chase(dog2); // Funciona: Perro persiguiendo a otro perro
}Ten cuidado, no obstante: el uso de covariant traslada la seguridad de tipos al tiempo de ejecución. Si llamas al método a través de una referencia de padre con el tipo incorrecto, obtendrás un error en tiempo de ejecución en lugar de un error en tiempo de compilación. Úsalo cuando estés seguro de los tipos que se están pasando.
Desafío
FácilVamos a construir un sistema de compatibilidad de mascotas que utiliza la palabra clave covariant para asegurar que las mascotas solo puedan jugar con las de su propia especie. Crearás una jerarquía de mascotas donde cada tipo tiene un método playWith que acepta solo el mismo tipo de mascota.
Organizarás tu código en dos archivos:
pets.dart: Define tu jerarquía de mascotas aquí:- Una clase
Petcon una propiedadString namey un constructor. Incluye un métodoplayWith(Pet other)que imprima'$name plays with ${other.name}' - Una clase
Catque extienda dePety sobrescribaplayWithusando la palabra clavecovariantpara aceptar solo unCat. Debe imprimir'$name and ${other.name} chase yarn together' - Una clase
Dogque extienda dePety sobrescribaplayWithusando la palabra clavecovariantpara aceptar solo unDog. Debe imprimir'$name and ${other.name} fetch the ball together' - Una clase
Rabbitque extienda dePety sobrescribaplayWithusando la palabra clavecovariantpara aceptar solo unRabbit. Debe imprimir'$name and ${other.name} hop around together'
- Una clase
main.dart: Importa tu archivo de mascotas y demuestra cómo cada tipo de mascota juega exclusivamente con los de su propia especie:- Crea dos objetos
Catllamados'Whiskers'y'Mittens', luego haz que Whiskers juegue con Mittens - Crea dos objetos
Dogllamados'Buddy'y'Max', luego haz que Buddy juegue con Max - Crea dos objetos
Rabbitllamados'Flopsy'y'Cotton', luego haz que Flopsy juegue con Cotton
- Crea dos objetos
La palabra clave covariant permite que cada subclase reduzca el tipo de parámetro de Pet a su tipo específico, asegurando interacciones seguras entre tipos de mascotas de la misma especie.
Salida esperada:
Whiskers and Mittens chase yarn together
Buddy and Max fetch the ball together
Flopsy and Cotton hop around togetherHoja de referencia
La palabra clave covariant permite que una subclase sobrescriba un método con un tipo de parámetro más específico que el de la clase padre.
Sin covariant, Dart requiere que los tipos de parámetros coincidan exactamente al sobrescribir métodos. Con covariant, puedes restringir el tipo de parámetro en la subclase:
class Animal {
void chase(Animal other) {
print('Chasing an animal');
}
}
class Dog extends Animal {
@override
void chase(covariant Dog other) {
print('Dog chasing another dog');
}
}Esto es útil cuando las subclases solo deben funcionar con su propio tipo:
void main() {
Dog dog1 = Dog();
Dog dog2 = Dog();
dog1.chase(dog2); // Funciona: Dog chasing another dog
}Importante: El uso de covariant traslada la seguridad de tipos del tiempo de compilación al tiempo de ejecución. Si llamas al método a través de una referencia del padre con el tipo incorrecto, obtendrás un error en tiempo de ejecución en lugar de un error en tiempo de compilación.
Pruébalo tú mismo
import 'pets.dart';
void main() {
// TODO: Crear dos objetos Cat llamados 'Whiskers' y 'Mittens'
// Luego haz que Whiskers juegue con Mittens
// TODO: Crear dos objetos Dog llamados 'Buddy' y 'Max'
// Luego haz que Buddy juegue con Max
// TODO: Crear dos objetos Rabbit llamados 'Flopsy' y 'Cotton'
// Luego haz que Flopsy juegue con Cotton
}
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