Constructeurs asynchrones
Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 79 sur 110.
Les constructeurs en Dart ne peuvent pas être marqués comme async - ils doivent retourner une instance de la classe immédiatement, et non un Future. Alors, comment créer des objets qui nécessitent une initialisation asynchrone, comme le chargement de données depuis une base de données ou la récupération d'une configuration ?
La solution consiste à utiliser une méthode de fabrique statique asynchrone. Gardez le constructeur privé (ou simple) et fournissez une méthode statique qui effectue le travail asynchrone et renvoie un Future de votre classe :
class UserProfile {
final String name;
final int age;
UserProfile._(this.name, this.age); // Constructeur privé
static Future<UserProfile> create(String userId) async {
// Simuler la récupération de données
await Future.delayed(Duration(seconds: 1));
return UserProfile._('Alice', 25);
}
}
Future<void> main() async {
var user = await UserProfile.create('123');
print(user.name); // Alice
}Le constructeur privé UserProfile._ gère la création réelle de l'objet, tandis que la méthode statique create() gère tout le travail asynchrone. Les appelants utilisent await pour obtenir l'objet entièrement initialisé.
Ce patron garantit que votre objet est complètement prêt à l'emploi une fois que vous l'avez - pas d'états partiellement initialisés ou de données manquantes. Il est couramment utilisé pour les classes qui doivent charger des ressources, se connecter à des services ou effectuer toute configuration qui prend du temps.
Défi
FacileConstruisons un chargeur de configuration qui démontre comment gérer l'initialisation asynchrone dans les classes ! Comme les constructeurs ne peuvent pas être asynchrones, vous utiliserez le modèle de méthode de fabrique statique (static factory method pattern) pour créer des objets qui ont besoin de temps pour "charger" leurs données.
Vous organiserez votre code en deux fichiers :
config_loader.dart: Créez une classeConfigLoaderqui simule le chargement de paramètres de configuration de manière asynchrone. Votre classe doit avoir :- Trois champs finaux :
appName(String),version(String), etmaxUsers(int) - Un constructeur privé qui initialise les trois champs
- Une méthode de fabrique statique asynchrone appelée
loadqui prend un paramètreString configIdet retourne unFuture<ConfigLoader>. Cette méthode doit :- Utiliser
Future.delayed()avec 100 millisecondes pour simuler le temps de chargement - Générer les valeurs de configuration basées sur le
configId:appName: le configId avec" App"ajouté à la finversion:"1.0."suivi de la longueur de configIdmaxUsers: la longueur de configId multipliée par 10
- Retourner une nouvelle instance de
ConfigLoaderavec ces valeurs
- Utiliser
- Une méthode
displayInfo()qui affiche la configuration dans ce format :Config: [appName] v[version] (max [maxUsers] users)
- Trois champs finaux :
main.dart: Importez votre chargeur de configuration et démontrez le modèle d'initialisation asynchrone :- Affichez
Loading configurations... - Chargez une configuration avec le configId
"Production"et appelez sa méthodedisplayInfo() - Chargez une configuration avec le configId
"Dev"et appelez sa méthodedisplayInfo() - Affichez
All configs loaded!
- Affichez
Remarquez comment la méthode statique load gère tout le travail asynchrone, tandis que le constructeur privé se contente d'assigner les valeurs. Les appelants utilisent await pour obtenir un objet entièrement initialisé !
Sortie attendue :
Loading configurations...
Config: Production App v1.0.10 (max 100 users)
Config: Dev App v1.0.3 (max 30 users)
All configs loaded!Aide-mémoire
Les constructeurs en Dart ne peuvent pas être marqués comme async car ils doivent retourner immédiatement une instance de la classe, et non un Future.
Pour créer des objets nécessitant une initialisation asynchrone, utilisez une méthode factory statique asynchrone :
class UserProfile {
final String name;
final int age;
UserProfile._(this.name, this.age); // Private constructor
static Future<UserProfile> create(String userId) async {
// Perform async work here
await Future.delayed(Duration(seconds: 1));
return UserProfile._('Alice', 25);
}
}Utilisation :
Future<void> main() async {
var user = await UserProfile.create('123');
print(user.name); // Alice
}Le constructeur privé (marqué par _) gère la création de l'objet, tandis que la méthode statique gère le travail asynchrone. Cela garantit que les objets sont entièrement initialisés avant leur utilisation.
Essayez vous-même
import 'config_loader.dart';
void main() async {
// TODO: Afficher "Loading configurations..."
// TODO: Charger une configuration avec le configId "Production"
// et appeler sa méthode displayInfo()
// TODO: Charger une configuration avec le configId "Dev"
// et appeler sa méthode displayInfo()
// TODO: Afficher "All configs loaded!"
}
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