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.
Défi
FacileConstruisons 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 typeSettingsopaque à l'aide d'une déclaration anticipée (le corps de la structure reste caché). Déclarez une fonctionget_settingsqui renvoie un pointeur vers l'instance singleton, ainsi que des fonctions getter et setter pour deux valeurs de configuration :volume(un entier) etbrightness(un entier). Les gardes d'inclusion sont essentiels ici.settings.c: C'est ici que la magie opère. Définissez la structureSettingsréelle avec les champsvolumeetbrightness. Créez une variable pointeurstaticpour contenir l'instance unique (initialisée àNULL). Implémentezget_settingsde 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é. Appelezget_settingsdeux 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 :
- La nouvelle valeur de volume
- 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
100Exemple de sortie lorsque les entrées sont 25 et 60 :
25
60Exemple de sortie lorsque les entrées sont 0 et 50 :
0
50L'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
NULLlors 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;
}
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
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercle