Classes génériques
Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 65 sur 110.
Vous avez vu comment les collections intégrées de Dart comme List<String> utilisent des paramètres de type. Il est maintenant temps de créer vos propres classes génériques qui fonctionnent avec n'importe quel type que vous spécifiez.
Une classe générique utilise un paramètre de type (généralement T) comme espace réservé pour le type réel qui sera fourni lors de la création d'une instance :
class Box<T> {
T content;
Box(this.content);
T getContent() => content;
}
void main() {
var stringBox = Box<String>('Hello');
var intBox = Box<int>(42);
print(stringBox.getContent()); // Hello
print(intBox.getContent()); // 42
}Le T agit comme une variable de type - lorsque vous créez Box<String>, chaque T dans la classe devient String. Cela vous offre une sécurité de type sans avoir à écrire des classes distinctes pour chaque type.
Vous pouvez utiliser plusieurs paramètres de type lorsque votre classe doit fonctionner avec plus d'un type :
class Pair<K, V> {
K first;
V second;
Pair(this.first, this.second);
}
void main() {
var pair = Pair<String, int>('age', 25);
print('${pair.first}: ${pair.second}'); // age: 25
}Les classes génériques sont le fondement d'un code réutilisable et sûr au niveau des types. Au lieu de dupliquer la logique pour différents types ou de perdre les informations de type avec dynamic, les génériques vous permettent d'écrire un code flexible que le compilateur peut toujours vérifier.
Défi
FacileConstruisons un système d'emballage de cadeaux qui utilise des classes génériques pour créer des conteneurs flexibles pour différents types d'articles. Vous allez créer une classe générique Wrapper capable d'envelopper n'importe quel type de contenu, et une classe GiftBox avec deux paramètres de type pour associer un cadeau à un message de carte.
Vous organiserez votre code dans deux fichiers :
wrapper.dart: Définissez vos classes génériques ici :- Une classe générique
Wrapper<T>avec une propriétéT contentet un constructeur. Incluez une méthodeunwrap()qui retourne le contenu, et une méthodedescribe()qui afficheWrapped: [content] - Une classe générique
GiftBox<G, C>avec deux propriétés :G giftetC card. Incluez un constructeur et une méthodeopen()qui afficheGift: [gift]sur une ligne etCard: [card]sur la ligne suivante
- Une classe générique
main.dart: Importez votre fichier wrapper et faites la démonstration des classes génériques avec différents types :- Créez un
Wrapper<String>contenant'Chocolate'et appelezdescribe() - Créez un
Wrapper<int>contenant42et appelezdescribe() - Créez un
Wrapper<double>contenant3.14et appelezdescribe() - Affichez une ligne vide
- Créez un
GiftBox<String, String>avec le cadeau'Teddy Bear'et la carte'Happy Birthday!', puis appelezopen() - Affichez une ligne vide
- Créez un
GiftBox<int, String>avec le cadeau100(représentant le montant d'une carte-cadeau) et la carte'Congratulations!', puis appelezopen()
- Créez un
Remarquez comment la même classe Wrapper fonctionne parfaitement avec des chaînes de caractères, des entiers et des doubles. La classe GiftBox démontre l'utilisation de deux paramètres de type pour associer différents types ensemble - le cadeau peut être de n'importe quel type tandis que le message de la carte reste une chaîne de caractères.
Sortie attendue :
Wrapped: Chocolate
Wrapped: 42
Wrapped: 3.14
Gift: Teddy Bear
Card: Happy Birthday!
Gift: 100
Card: Congratulations!Aide-mémoire
Les classes génériques utilisent des paramètres de type (comme T) comme substituts pour les types réels spécifiés lors de la création des instances :
class Box<T> {
T content;
Box(this.content);
T getContent() => content;
}
void main() {
var stringBox = Box<String>('Hello');
var intBox = Box<int>(42);
print(stringBox.getContent()); // Hello
print(intBox.getContent()); // 42
}Lorsque vous créez Box<String>, chaque T dans la classe devient String, offrant une sécurité de type sans avoir besoin de classes distinctes pour chaque type.
Utilisez plusieurs paramètres de type lorsque vous travaillez avec plus d'un type :
class Pair<K, V> {
K first;
V second;
Pair(this.first, this.second);
}
void main() {
var pair = Pair<String, int>('age', 25);
print('${pair.first}: ${pair.second}'); // age: 25
}Essayez vous-même
import 'wrapper.dart';
void main() {
// TODO: Créer un Wrapper<String> contenant 'Chocolate' et appeler describe()
// TODO: Créer un Wrapper<int> contenant 42 et appeler describe()
// TODO: Créer un Wrapper<double> contenant 3.14 et appeler describe()
// TODO: Afficher une ligne vide
// TODO: Créer un GiftBox<String, String> avec le cadeau 'Teddy Bear'
// et la carte 'Happy Birthday!', puis appeler open()
// TODO: Afficher une ligne vide
// TODO: Créer un GiftBox<int, String> avec le cadeau 100
// et la carte 'Congratulations!', puis appeler open()
}
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