Patron Singleton
Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 54 sur 61.
Parfois, vous avez besoin d’exactement une instance d’un objet dans l’ensemble de votre programme : un gestionnaire de configuration, un système de journalisation ou une connexion à une base de données. Le modèle Singleton garantit qu’une seule instance existe et fournit un point d’accès global à celle-ci.
En C, nous implémentons cela à l’aide d’une variable static à l’intérieur d’un fichier source. Souviens-toi qu’un 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é à 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 renvoie le même pointeur.
Le mot-clé static garantit que instance conserve sa valeur entre les appels de fonction et reste masqué aux autres fichiers.
Depuis l’en-tête, les utilisateurs ne voient que la fonction getter. Ils ne peuvent pas accéder directement à la variable statique ni la modifier. Quel que soit le nombre de fois où vous appelez get_config() ou l’endroit depuis lequel vous l’appelez, vous obtenez toujours le même objet.
Défi
FacileConstruisons un module Settings qui gère la configuration globale de l’application à l’aide du modèle Singleton. Quel que soit le nombre de fois où votre code demande les paramètres, il doit toujours recevoir exactement la même instance.
Vous organiserez votre code dans trois fichiers :
settings.h: Déclarez un type opaqueSettingsà l’aide d’une déclaration anticipée (le corps de la structure reste masqué). Déclarez une fonctionget_settingsqui renvoie un pointeur vers l’instance singleton, ainsi que des fonctions d’accès et de modification pour deux valeurs de configuration :volume(un entier) etbrightness(un entier). Les gardes d’inclusion sont indispensables ici.settings.c: C’est ici que la magie opère. Définissez la structureSettingsréelle avec les champsvolumeetbrightness. Créez une variable pointeurstaticdestinée à contenir l’instance unique (initialisée àNULL). Implémentezget_settingsafin que le premier appel alloue et initialise l’instance avec les valeurs par défaut (volume : 50, brightness : 75), tandis que les appels suivants renvoient simplement l’instance existante. Implémentez les fonctions d’accès et de modification pour accéder aux champs masqués et les modifier.main.c: Démontrez que le Singleton fonctionne correctement. Lisez deux entiers représentant les nouvelles valeurs du volume et de la luminosité. Appelezget_settingsdeux fois, en stockant les résultats dans deux variables pointeur différentes. Utilisez le premier pointeur pour mettre à jour le volume et la luminosité avec les valeurs saisies. 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 du volume
- La nouvelle valeur de la 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 essentielle est que les deux pointeurs pointent vers le même objet en mémoire : c’est l’essence du modèle Singleton. La variable statique à l’intérieur de votre fichier source garantit qu’une seule instance existe, et qu’elle persiste pendant toute la durée de vie du programme.
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: Appelez get_settings deux fois et stockez dans deux variables pointeur différentes
// TODO: Utilisez le premier pointeur pour mettre à jour volume et brightness avec les valeurs d'entrée
// TODO: Utilisez 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 Programmation Orientée Objet
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 cercleImplémentation du rectangleUtilisation polymorpheConteneur de formesEntraînez-vous par vous-même : Compilateur C en ligne