Menu
Coddy logo textTech

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)); // true

Dans 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.

challenge icon

Défi

Facile

Construisons 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 classe Notification qui sert de base à tous les types de notifications. Votre classe doit avoir :
    • Un champ String message
    • Un constructeur nommé privé Notification._internal qui initialise le message
    • Un constructeur factory Notification(String type, String message) qui retourne différents sous-types de notification basés sur le paramètre type :
      • Si le type est 'email', retournez une EmailNotification
      • Si le type est 'sms', retournez une SMSNotification
      • Sinon, retournez une PushNotification
    • Une méthode send() qui affiche Sending: [message]

Dans le même fichier, créez trois sous-classes qui étendent Notification :

  • EmailNotification : Surchargez send() pour afficher Email: [message]
  • SMSNotification : Surchargez send() pour afficher SMS: [message]
  • PushNotification : Surchargez send() pour afficher Push: [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'
    Appelez send() sur chaque notification dans l'ordre listé ci-dessus.

Sortie attendue :

Email: Welcome!
SMS: Your code is 1234
Push: New update available

Aide-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)); // true

Retourner 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
}
quiz iconTestez-vous

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