Mot-clé covariant
Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 61 sur 110.
Lorsque vous redéfinissez une méthode dans une sous-classe, Dart exige normalement que les types de paramètres correspondent exactement. Mais parfois, vous souhaitez qu'une méthode de sous-classe accepte un type plus spécifique que le parent. Le mot-clé covariant permet cela.
Considérez un scénario où une classe Animal possède une méthode qui accepte un autre 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');
}
}Sans covariant, Dart se plaindrait que Dog n'est pas du même type que Animal. En ajoutant covariant avant le paramètre, vous dites à Dart : « Je sais que c'est plus spécifique, et je m'assurerai que seul le bon type est transmis. »
Ceci est utile lorsque les sous-classes ne devraient logiquement fonctionner qu'avec leur propre type :
void main() {
Dog dog1 = Dog();
Dog dog2 = Dog();
dog1.chase(dog2); // Fonctionne : Un chien en poursuit un autre
}Soyez toutefois prudent : l'utilisation de covariant déplace la sécurité de type au moment de l'exécution. Si vous appelez la méthode via une référence parente avec le mauvais type, vous obtiendrez une erreur d'exécution au lieu d'une erreur de compilation. Utilisez-le lorsque vous êtes certain des types transmis.
Défi
FacileConstruisons un système de compatibilité pour animaux de compagnie qui utilise le mot-clé covariant pour garantir que les animaux ne peuvent jouer qu'avec leurs semblables. Vous allez créer une hiérarchie d'animaux où chaque type possède une méthode playWith qui n'accepte que le même type d'animal.
Vous organiserez votre code en deux fichiers :
pets.dart: Définissez votre hiérarchie d'animaux ici :- Une classe
Petavec une propriétéString nameet un constructeur. Incluez une méthodeplayWith(Pet other)qui affiche[name] plays with [other.name] - Une classe
Catqui étendPetet redéfinitplayWithen utilisant le mot-clécovariantpour n'accepter qu'unCat. Elle doit afficher[name] and [other.name] chase yarn together - Une classe
Dogqui étendPetet redéfinitplayWithen utilisant le mot-clécovariantpour n'accepter qu'unDog. Elle doit afficher[name] and [other.name] fetch the ball together - Une classe
Rabbitqui étendPetet redéfinitplayWithen utilisant le mot-clécovariantpour n'accepter qu'unRabbit. Elle doit afficher[name] and [other.name] hop around together
- Une classe
main.dart: Importez votre fichier d'animaux et démontrez comment chaque type d'animal joue exclusivement avec ses semblables :- Créez deux objets
Catnommés'Whiskers'et'Mittens', puis faites jouer Whiskers avec Mittens - Créez deux objets
Dognommés'Buddy'et'Max', puis faites jouer Buddy avec Max - Créez deux objets
Rabbitnommés'Flopsy'et'Cotton', puis faites jouer Flopsy avec Cotton
- Créez deux objets
Le mot-clé covariant permet à chaque sous-classe de restreindre le type de paramètre de Pet vers son type spécifique, garantissant des interactions de type sécurisé entre les animaux de la même espèce.
Sortie attendue :
Whiskers and Mittens chase yarn together
Buddy and Max fetch the ball together
Flopsy and Cotton hop around togetherAide-mémoire
Le mot-clé covariant permet à une sous-classe de redéfinir une méthode avec un type de paramètre plus spécifique que celui de la classe parente.
Sans covariant, Dart exige que les types de paramètres correspondent exactement lors de la redéfinition des méthodes. Avec covariant, vous pouvez restreindre le type de paramètre dans la sous-classe :
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');
}
}C'est utile lorsque les sous-classes ne doivent travailler qu'avec leur propre type :
void main() {
Dog dog1 = Dog();
Dog dog2 = Dog();
dog1.chase(dog2); // Fonctionne : Dog chasing another dog
}Important : L'utilisation de covariant déplace la sécurité de type de la compilation vers l'exécution. Si vous appelez la méthode via une référence parente avec le mauvais type, vous obtiendrez une erreur d'exécution au lieu d'une erreur de compilation.
Essayez vous-même
import 'pets.dart';
void main() {
// TODO: Créer deux objets Cat nommés 'Whiskers' et 'Mittens'
// Ensuite, faire en sorte que Whiskers joue avec Mittens
// TODO: Créer deux objets Dog nommés 'Buddy' et 'Max'
// Ensuite, faire en sorte que Buddy joue avec Max
// TODO: Créer deux objets Rabbit nommés 'Flopsy' et 'Cotton'
// Ensuite, faire en sorte que Flopsy joue avec Cotton
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Les bases de la POO
Fichiers externesBibliothèques et importsIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesVariables d'instanceBases des constructeursRécapitulatif - Calculatrice simple4Null Safety
Introduction à la Null SafetyNullable vs Non-NullableLes opérateurs ? et !Le mot-clé late et la Null SafetyLes opérateurs Null-AwareLa Null Safety dans les classesRécapitulatif - Système de profil utilisateur7Classes abstraites et Interfaces
Classes abstraitesMéthodes abstraitesInterfaces en DartInterfaces implicitesImplémentation vs ExtensionInterfaces multiplesRécapitulatif - Calculateur de formes10Collections et Génériques
Aperçu des List, Set et MapCollections Type-SafeClasses génériquesMéthodes génériquesContraintes de généricitéIterable & IteratorRécapitulatif - Stockage générique2Les constructeurs en Dart
Constructeur par défautConstructeurs nommésListes d'initialisationConstructeurs constantsConstructeurs factoryConstructeurs de redirectionRécapitulatif - Shape Builder5Encapsulation
Membres publics vs privésLa convention du préfixe _Visibilité au niveau de la bibliothèqueApprofondissement des Getters & SettersMasquage d'informationsRécapitulatif - Dossiers d'étudiants8Mixins
Introduction aux MixinsCréation de MixinsUtilisation de plusieurs MixinsLe mot-clé on dans les MixinsMixin vs HéritageMixin vs InterfaceRécapitulatif - Système Animal11Méthodes spéciales
Redéfinition de toString()Redéfinition de hashCode & ==Interface ComparableMéthode call()Redéfinition de noSuchMethodRécapitulatif - Collection personnalisée14Patrons de conception Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron ObservateurPatron Stratégie3Propriétés de classe
Membres d'instance vs statiquesChamps Final & ConstVariables LateMéthodes et champs statiquesGetters et SettersRécapitulatif - Gestionnaire de compte bancaire6Héritage
Bases de l'héritageLe mot-clé superRedéfinition de méthodeL'annotation @overrideLe mot-clé final pour les classesConstructeurs et héritageRécapitulatif - Hiérarchie des employés9Polymorphisme
Bases du polymorphismePolymorphisme via les interfacesVérification de type à l'exécutionLes opérateurs is & asMot-clé covariantRécapitulatif - Processeur de paiement12POO Asynchrone
Futures & async/awaitBases des StreamsStream ControllersConstructeurs asynchronesL'asynchrone dans les méthodes de classeRécapitulatif - Data Fetcher15Patrons de conception Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode ModèlePatron ÉtatPatron CompositePatron Repository