Menu
Coddy logo textTech

Patron Singleton

Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 65 sur 87.

Le Singleton Pattern est un patron de conception de création qui garantit qu'une classe n'a qu'une seule instance tout au long de votre application, tout en fournissant un point d'accès global à cette instance. Cela est utile pour les ressources qui doivent être partagées, comme les gestionnaires de configuration, les pools de connexion ou les services de journalisation.

Le patron fonctionne en rendant le constructeur privé, empêchant ainsi l'instanciation directe. À la place, une méthode statique contrôle l'accès à l'instance unique :

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // Le constructeur privé empêche l'instanciation directe
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // Point d'accès global
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

Chaque appel à getInstance() retourne le même objet. L'instance est créée uniquement lors de la première demande — c'est ce qu'on appelle l'initialisation paresseuse :

DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();

System.out.println(db1 == db2);  // true - même instance

Les composants clés d'un Singleton sont : un champ private static contenant l'instance, un constructeur private, et une méthode public static qui retourne l'instance. Cette combinaison garantit que peu importe le nombre de fois que vous demandez l'objet, vous obtenez toujours le même.

challenge icon

Défi

Facile

Construisons un gestionnaire de configuration pour une application en utilisant le Singleton Pattern ! Votre gestionnaire de configuration garantira que toutes les parties de votre application partagent les mêmes paramètres, quel que soit le nombre de fois qu'elles demandent à y accéder.

Vous organiserez votre code sur deux fichiers :

  • AppConfig.java : Créez une classe Singleton qui gère les paramètres de configuration de l'application. Votre AppConfig doit avoir :

    Un champ statique privé pour contenir l'instance unique.

    Un champ String privé appelé appName et un champ int privé appelé maxUsers.

    Un constructeur privé qui initialise appName à "MyApplication" et maxUsers à 100, puis affiche AppConfig initialized.

    Une méthode statique publique getInstance() qui crée l'instance uniquement si elle n'existe pas encore (initialisation paresseuse), puis la retourne.

    Une méthode setAppName(String name) qui met à jour le nom de l'application.

    Une méthode setMaxUsers(int max) qui met à jour le nombre maximum d'utilisateurs.

    Une méthode displaySettings() qui affiche App: [appName], Max Users: [maxUsers].

  • Main.java : Démontrez que votre Singleton fonctionne correctement ! Vous recevrez deux entrées : un nouveau nom d'application (String) et une nouvelle valeur de nombre maximum d'utilisateurs (entier).

    Tout d'abord, obtenez une instance de AppConfig et stockez-la dans une variable appelée config1. Appelez displaySettings() pour afficher les valeurs par défaut.

    Ensuite, mettez à jour les paramètres en utilisant vos valeurs d'entrée en appelant setAppName et setMaxUsers sur config1.

    Obtenez une autre instance et stockez-la dans config2. Appelez displaySettings() sur config2 pour prouver qu'elle reflète les modifications effectuées via config1.

    Enfin, affichez si les deux références pointent vers le même objet : Same instance: [true/false] en comparant config1 == config2.

Vous recevrez deux entrées dans l'ordre : le nouveau nom de l'application (String) et le nouveau nombre maximum d'utilisateurs (entier).

Ce défi démontre l'avantage principal du Singleton Pattern : peu importe le nombre de fois que vous demandez la configuration, vous obtenez toujours la même instance avec le même état partagé !

Aide-mémoire

Le Singleton Pattern (Patron de conception Singleton) garantit qu'une classe n'a qu'une seule instance dans toute l'application, fournissant un point d'accès global à cette instance.

Composants clés :

  • Un champ private static contenant l'unique instance
  • Un constructeur private pour empêcher l'instanciation directe
  • Une méthode public static qui retourne l'instance

Implémentation de base :

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    // Le constructeur privé empêche l'instanciation directe
    private DatabaseConnection() {
        System.out.println("Connection created");
    }
    
    // Point d'accès global
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    
    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

Utilisation :

DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();

System.out.println(db1 == db2);  // true - même instance

L'instance n'est créée que lors de la première demande — c'est ce qu'on appelle l'initialisation paresseuse (lazy initialization). Chaque appel à getInstance() retourne le même objet, garantissant un état partagé dans toute l'application.

Essayez vous-même

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Lire les entrées
        String newAppName = scanner.nextLine();
        int newMaxUsers = scanner.nextInt();
        
        // TODO: Obtenir la première instance de AppConfig et la stocker dans config1
        
        // TODO: Appeler displaySettings() sur config1 pour afficher les valeurs par défaut
        
        // TODO: Mettre à jour les paramètres en utilisant setAppName et setMaxUsers sur config1
        
        // TODO: Obtenir une autre instance et la stocker dans config2
        
        // TODO: Appeler displaySettings() sur config2 pour prouver que les modifications sont partagées
        
        // TODO: Afficher si les deux références pointent vers le même objet :
        // "Same instance: [true/false]" en utilisant config1 == config2
    }
}
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