Constructeurs factory
Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 14 sur 110.
Un constructeur factory est un constructeur spécial qui ne crée pas toujours une nouvelle instance. Contrairement aux constructeurs classiques, un constructeur factory peut retourner une instance existante, un sous-type, ou même null (s'il est nullable). Vous le déclarez en utilisant le mot-clé factory.
class Logger {
static final Logger _instance = Logger._internal();
// Constructeur nommé privé
Logger._internal();
// Constructeur d'usine (factory)
factory Logger() {
return _instance;
}
}
Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // trueDans cet exemple, le constructeur d'usine (factory) retourne toujours la même instance. Peu importe le nombre de fois que vous appelez Logger(), vous obtenez l'objet identique. Ce modèle est couramment utilisé pour implémenter des singletons.
Les constructeurs de type factory diffèrent des constructeurs classiques d'une manière essentielle : ils n'ont pas accès à this car ils pourraient ne pas créer de nouvelle instance du tout. Au lieu de cela, ils doivent explicitement retourner un objet :
class Shape {
factory Shape(String type) {
if (type == 'circle') return Circle();
if (type == 'square') return Square();
return Rectangle();
}
}
class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }Les constructeurs factory sont utiles lorsque vous avez besoin de contrôler la création d'instances, comme pour retourner des objets mis en cache, implémenter des pools d'objets ou décider quel sous-type instancier en fonction des paramètres d'entrée.
Défi
FacileConstruisons un système de notification qui utilise des constructeurs d'usine (factory constructors) pour créer différents types de notifications basés sur une simple entrée de chaîne de caractères.
Vous allez créer deux fichiers pour organiser votre code :
notification.dart: Définissez une classeNotificationqui sert de base à tous les types de notifications. Votre classe doit avoir :- Un champ
String message - Un constructeur nommé privé
Notification._internalqui initialise le message - Un constructeur factory
Notification(String type, String message)qui retourne différents sous-types de notification basés sur le paramètretype:- Si le type est
'email', retournez uneEmailNotification - Si le type est
'sms', retournez uneSMSNotification - Sinon, retournez une
PushNotification
- Si le type est
- Une méthode
send()qui afficheSending: [message]
- Un champ
Dans le même fichier, créez trois sous-classes qui étendent Notification :
EmailNotification: Surchargezsend()pour afficherEmail: [message]SMSNotification: Surchargezsend()pour afficherSMS: [message]PushNotification: Surchargezsend()pour afficherPush: [message]
Chaque sous-classe a besoin d'un constructeur qui prend un message et le transmet au parent en utilisant super._internal(message).
main.dart: Importez votre classe de notification et créez trois notifications en utilisant le constructeur factory :- Une notification par e-mail avec le message
'Welcome!' - Une notification par SMS avec le message
'Your code is 1234' - Une notification push avec le message
'New update available'
send()sur chaque notification dans l'ordre listé ci-dessus.- Une notification par e-mail avec le message
Sortie attendue :
Email: Welcome!
SMS: Your code is 1234
Push: New update availableAide-mémoire
Un constructeur factory est un constructeur spécial déclaré avec le mot-clé factory qui ne crée pas toujours une nouvelle instance. Contrairement aux constructeurs réguliers, il peut retourner une instance existante, un sous-type ou null.
Les constructeurs factory n'ont pas accès à this et doivent explicitement retourner un objet.
Exemple de pattern Singleton :
class Logger {
static final Logger _instance = Logger._internal();
Logger._internal(); // Constructeur nommé privé
factory Logger() {
return _instance; // Retourne toujours la même instance
}
}
Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // trueRetourner différents sous-types :
class Shape {
factory Shape(String type) {
if (type == 'circle') return Circle();
if (type == 'square') return Square();
return Rectangle();
}
}
class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }Les constructeurs factory sont utiles pour contrôler la création d'instances, comme le retour d'objets mis en cache, l'implémentation de pools d'objets ou la décision du sous-type à instancier en fonction des paramètres d'entrée.
Essayez vous-même
import 'notification.dart';
void main() {
// TODO: Créer une notification par e-mail avec le message 'Welcome!'
// TODO: Créer une notification par SMS avec le message 'Your code is 1234'
// TODO: Créer une notification push avec le message 'New update available'
// TODO: Appeler send() sur chaque notification dans l'ordre
}
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