Menu
Coddy logo textTech

Patron Singleton

Fait partie de la section Object Oriented Programming du Journey C de Coddy — leçon 54 sur 61.

Parfois, vous avez besoin d'exactement une seule instance d'un objet tout au long de votre programme — un gestionnaire de configuration, un système de journalisation ou une connexion à une base de données. Le patron Singleton garantit qu'une seule instance existe et fournit un point d'accès global à celle-ci.

En C, nous implémentons cela en utilisant une variable static à l'intérieur d'un fichier source. Rappelez-vous que static à la portée du fichier signifie que la variable est privée à ce fichier et persiste pendant toute la durée de vie du programme. Combiné avec une fonction getter, cela crée notre Singleton :

// config.c
#include "config.h"
#include <stdlib.h>

struct Config {
    int max_connections;
    int timeout;
};

static Config* instance = NULL;

Config* get_config(void) {
    if (instance == NULL) {
        instance = malloc(sizeof(Config));
        instance->max_connections = 100;
        instance->timeout = 30;
    }
    return instance;
}

La magie opère dans get_config(). Le premier appel crée et initialise l'instance. Chaque appel suivant retourne le même pointeur.

Le mot-clé static garantit que instance conserve sa valeur entre les appels de fonction et reste masqué pour les autres fichiers.

Depuis l'en-tête, les utilisateurs ne voient que la fonction getter — ils ne peuvent pas accéder à la variable statique ni la modifier directement. Peu importe le nombre de fois ou l'endroit d'où vous appelez get_config(), vous obtenez toujours le même objet.

challenge icon

Défi

Facile

Construisons un module Settings qui gère la configuration à l'échelle de l'application en utilisant le motif Singleton. Peu importe le nombre de fois que votre code demande les paramètres, il doit toujours recevoir exactement la même instance.

Vous organiserez votre code sur trois fichiers :

  • settings.h : Déclarez un type Settings opaque à l'aide d'une déclaration anticipée (le corps de la structure reste caché). Déclarez une fonction get_settings qui renvoie un pointeur vers l'instance singleton, ainsi que des fonctions getter et setter pour deux valeurs de configuration : volume (un entier) et brightness (un entier). Les gardes d'inclusion sont essentiels ici.
  • settings.c : C'est ici que la magie opère. Définissez la structure Settings réelle avec les champs volume et brightness. Créez une variable pointeur static pour contenir l'instance unique (initialisée à NULL). Implémentez get_settings de sorte que le premier appel alloue et initialise l'instance avec des valeurs par défaut (volume : 50, brightness : 75), tandis que les appels suivants renvoient simplement l'instance existante. Implémentez les getters et setters pour accéder aux champs cachés et les modifier.
  • main.c : Démontrez que le Singleton fonctionne correctement. Lisez deux entiers représentant les nouvelles valeurs de volume et de luminosité. Appelez get_settings deux fois, en stockant les résultats dans deux variables pointeurs différentes. Utilisez le premier pointeur pour mettre à jour le volume et la luminosité avec les valeurs d'entrée. Utilisez ensuite le second pointeur pour récupérer et afficher les deux valeurs. Si le Singleton fonctionne, les modifications effectuées via un pointeur seront visibles via l'autre.

Votre programme recevra deux entrées :

  1. La nouvelle valeur de volume
  2. La nouvelle valeur de luminosité

Affichez le volume et la luminosité sur des lignes séparées après les avoir modifiés via un pointeur et lus via un autre.

Exemple de sortie lorsque les entrées sont 80 et 100 :

80
100

Exemple de sortie lorsque les entrées sont 25 et 60 :

25
60

Exemple de sortie lorsque les entrées sont 0 et 50 :

0
50

L'idée clé est que les deux pointeurs pointent vers le même objet en mémoire — c'est l'essence même du motif Singleton. La variable statique à l'intérieur de votre fichier source garantit qu'une seule instance n'existe jamais, et elle persiste pendant toute la durée de vie du programme.

Aide-mémoire

Le patron Singleton garantit qu'une seule instance d'un objet existe tout au long du programme et fournit un point d'accès global à celle-ci.

En C, implémentez un Singleton en utilisant une variable static à l'intérieur d'un fichier source combinée à une fonction getter :

// config.c
#include "config.h"
#include <stdlib.h>

struct Config {
    int max_connections;
    int timeout;
};

static Config* instance = NULL;

Config* get_config(void) {
    if (instance == NULL) {
        instance = malloc(sizeof(Config));
        instance->max_connections = 100;
        instance->timeout = 30;
    }
    return instance;
}

Points clés :

  • Le mot-clé static à la portée du fichier rend la variable privée à ce fichier et persistante pendant toute la durée de vie du programme
  • La fonction getter vérifie si l'instance est NULL lors du premier appel, la crée et l'initialise, puis la retourne
  • Les appels suivants retournent le même pointeur
  • Les utilisateurs ne voient la fonction getter qu'à travers l'en-tête — ils ne peuvent pas accéder à la variable statique ou la modifier directement
  • Peu importe le nombre de fois ou l'endroit d'où vous appelez le getter, vous obtenez toujours le même objet

Essayez vous-même

#include <stdio.h>
#include "settings.h"

int main() {
    int new_volume, new_brightness;
    scanf("%d", &new_volume);
    scanf("%d", &new_brightness);
    
    // TODO: Appeler get_settings deux fois et stocker le résultat dans deux variables pointeurs différentes
    
    
    // TODO: Utiliser le premier pointeur pour mettre à jour volume et brightness avec les valeurs saisies
    
    
    // TODO: Utiliser le second pointeur pour récupérer et afficher volume et brightness
    // (Ceci démontre que les deux pointeurs pointent vers la même instance singleton)
    
    
    return 0;
}
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 Object Oriented Programming