Menu
Coddy logo textTech

Patron Singleton

Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 90 sur 110.

Le pattern Singleton garantit qu'une classe n'a qu'une seule instance dans toute votre application et fournit un point d'accès global à celle-ci. C'est utile lorsqu'un seul objet est nécessaire pour coordonner les actions à travers le système - comme un gestionnaire de configuration, une connexion à une base de données ou un service de journalisation.

En Dart, vous pouvez implémenter un Singleton en utilisant un constructeur de type factory combiné à une instance statique privée :

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Constructeur nommé privé
  AppConfig._internal();
  
  // Le constructeur factory retourne la même instance
  factory AppConfig() {
    return _instance;
  }
}

void main() {
  var config1 = AppConfig();
  var config2 = AppConfig();
  
  config1.appName = 'UpdatedApp';
  
  print(config2.appName);  // UpdatedApp
  print(identical(config1, config2));  // true
}

Le constructeur privé _internal() empêche l'instanciation externe. Le champ statique _instance contient l'instance unique, créée une seule fois lors du chargement de la classe. Chaque appel à AppConfig() retourne cette même instance, de sorte que les modifications effectuées via une référence sont visibles partout.

Utilisez les Singletons avec parcimonie - ils introduisent un état global, ce qui peut rendre les tests plus difficiles. Ils sont mieux adaptés aux ressources véritablement partagées qui nécessitent un état cohérent dans toute votre application.

challenge icon

Défi

Facile

Construisons un gestionnaire de paramètres de jeu en utilisant le motif Singleton ! Vous allez créer un système qui garantit qu'une seule instance des paramètres de jeu existe dans toute l'application, afin que toutes les parties de votre jeu partagent la même configuration.

Vous organiserez votre code en deux fichiers :

  • game_settings.dart : Créez une classe GameSettings qui implémente le motif Singleton. Votre gestionnaire de paramètres doit comporter :
    • Une instance statique finale privée qui détient l'unique objet GameSettings
    • Un constructeur nommé privé pour empêcher l'instanciation externe
    • Un constructeur d'usine (factory) qui retourne toujours la même instance
    • Trois champs de paramètres : difficulty (String, par défaut : "Normal"), soundEnabled (bool, par défaut : true), et playerName (String, par défaut : "Player1")
    • Une méthode displaySettings() qui affiche les paramètres actuels sous ce format : Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off] (affichez "on" si soundEnabled est true, "off" si false)
  • main.dart : Importez vos paramètres de jeu et démontrez que le Singleton fonctionne correctement :
    • Récupérez l'instance des paramètres et nommez-la settings1
    • Appelez displaySettings() pour afficher les valeurs par défaut
    • Modifiez les paramètres : changez playerName en "Hero", difficulty en "Hard", et soundEnabled en false
    • Récupérez une autre référence aux paramètres et nommez-la settings2
    • Appelez displaySettings() sur settings2 pour prouver qu'il reflète les modifications apportées via settings1
    • Affichez si settings1 et settings2 sont identiques en utilisant : Same instance: [true/false]

Cela démontre l'avantage principal des Singletons : les modifications apportées n'importe où dans votre application sont immédiatement visibles partout ailleurs, car il n'y a qu'une seule instance !

Sortie attendue :

Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: true

Aide-mémoire

Le pattern Singleton garantit qu'une classe n'a qu'une seule instance dans toute votre application et fournit un point d'accès global à celle-ci.

En Dart, implémentez un Singleton en utilisant un constructeur factory combiné à une instance statique privée :

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Private named constructor
  AppConfig._internal();
  
  // Factory constructor returns the same instance
  factory AppConfig() {
    return _instance;
  }
}

Composants clés :

  • static final _instance : Détient l'instance unique, créée une seule fois lors du chargement de la classe
  • _internal() : Le constructeur privé empêche l'instanciation externe
  • factory AppConfig() : Retourne la même instance à chaque fois

Exemple d'utilisation :

var config1 = AppConfig();
var config2 = AppConfig();

config1.appName = 'UpdatedApp';

print(config2.appName);  // UpdatedApp
print(identical(config1, config2));  // true

Les modifications effectuées via une référence sont visibles partout car toutes les références pointent vers la même instance.

Essayez vous-même

import 'game_settings.dart';

void main() {
  // TODO: Récupérer l'instance de settings et l'appeler settings1
  
  // TODO: Appeler displaySettings() pour afficher les valeurs par défaut
  
  // TODO: Modifier les paramètres :
  // - Changer playerName en "Hero"
  // - Changer difficulty en "Hard"
  // - Changer soundEnabled en false
  
  // TODO: Récupérer une autre référence à settings et l'appeler settings2
  
  // TODO: Appeler displaySettings() sur settings2 pour prouver qu'il reflète les changements
  
  // TODO: Afficher si settings1 et settings2 sont identiques
  // Format : Same instance: [true/false]
}
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