Pattern Singleton
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 54 di 61.
A volte hai bisogno di una sola istanza di un oggetto in tutto il programma: un gestore della configurazione, un sistema di logging o una connessione al database. Il pattern Singleton garantisce che esista una sola istanza e fornisce un punto di accesso globale a essa.
In C, lo implementiamo usando una variabile static all’interno di un file sorgente. Ricorda che static a livello di file significa che la variabile è privata di quel file e persiste per tutta la durata del programma. In combinazione con una funzione getter, questo crea il nostro 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 magia avviene in get_config(). La prima chiamata crea e inizializza l’istanza. Ogni chiamata successiva restituisce lo stesso puntatore.
La parola chiave static garantisce che instance mantenga il suo valore tra una chiamata di funzione e l’altra e rimanga nascosta agli altri file.
Dall’header, gli utenti vedono solo la funzione getter. Non possono accedere direttamente alla variabile statica né modificarla. Indipendentemente da quante volte o da dove chiami get_config(), ottieni sempre lo stesso oggetto.
Sfida
FacileCreiamo un modulo Settings che gestisce la configurazione dell'intera applicazione usando il pattern Singleton. Indipendentemente dal numero di volte in cui il codice richiede le impostazioni, dovrebbe ricevere sempre la stessa identica istanza.
Organizzerai il codice in tre file:
settings.h: dichiara un tipoSettingsopaco usando una dichiarazione anticipata (il corpo della struct rimane nascosto). Dichiara una funzioneget_settingsche restituisce un puntatore all'istanza singleton, oltre a funzioni getter e setter per due valori di configurazione:volume(un intero) ebrightness(un intero). Le protezioni contro le inclusioni multiple sono essenziali.settings.c: è qui che avviene la magia. Definisci la structSettingseffettiva con i campivolumeebrightness. Crea una variabile puntatorestaticche contenga l'unica istanza (inizializzata aNULL). Implementaget_settingsin modo che la prima chiamata allochi e inizializzi l'istanza con valori predefiniti (volume: 50, brightness: 75), mentre le chiamate successive restituiscano semplicemente l'istanza esistente. Implementa le funzioni getter e setter per accedere ai campi nascosti e modificarli.main.c: dimostra che il Singleton funziona correttamente. Leggi due interi che rappresentano i nuovi valori di volume e luminosità. Chiamaget_settingsdue volte, memorizzando i risultati in due variabili puntatore diverse. Usa il primo puntatore per aggiornare il volume e la luminosità con i valori di input. Poi usa il secondo puntatore per recuperare e stampare entrambi i valori. Se il Singleton funziona, le modifiche apportate tramite un puntatore saranno visibili anche tramite l'altro.
Il programma riceverà due input:
- Il nuovo valore del volume
- Il nuovo valore della luminosità
Stampa il volume e la luminosità su righe separate dopo averli modificati tramite un puntatore e averli letti tramite un altro.
Esempio di output quando gli input sono 80 e 100:
80
100Esempio di output quando gli input sono 25 e 60:
25
60Esempio di output quando gli input sono 0 e 50:
0
50L'idea fondamentale è che entrambi i puntatori puntano allo stesso oggetto in memoria: questa è l'essenza del pattern Singleton. La variabile statica all'interno del file sorgente garantisce che esista sempre una sola istanza e che questa persista per tutta la durata del programma.
Provalo tu
#include <stdio.h>
#include "settings.h"
int main() {
int new_volume, new_brightness;
scanf("%d", &new_volume);
scanf("%d", &new_brightness);
// TODO: Call get_settings twice and store in two different pointer variables
// TODO: Use the first pointer to update volume and brightness with input values
// TODO: Use the second pointer to retrieve and print volume and brightness
// (This demonstrates that both pointers point to the same singleton instance)
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Basi di programmazione modulare
File di intestazioneGuardie di inclusioneFile sorgenteFunzioni staticheRipasso: calcolatrice modulare4Incapsulamento
Il concetto di puntatori opachiDefinire struct opacheGetter e setterLa convalida nei setterRiepilogo: scatola segreta2Oggetti e metodi
Le struct come oggettiIl puntatore 'Self'Correttezza constPuntatore o valoreMetodi di supportoRiepilogo: gestore di punti5Progetto: Conto bancario semplice
Configurazione del progettoImplementazione del conto8Polimorfismo
Puntatori a funzione nelle structSimulare i metodiIl concetto di interfacciaImplementare le interfacceIterazione polimorficaRiepilogo: Greeter11Pattern di progettazione in C
Pattern SingletonPattern FactoryPattern IteratorRiepilogo: Factory di Logger3Ciclo di vita degli oggetti
Pattern del costruttorePattern del distruttoreInizializzazione sullo stackCopia profondaRiepilogo: wrapper di stringhe6Ereditarietà tramite composizione
Incorporamento delle structLa regola del primo membroAccesso ai membri della classe baseUpcastingRiepilogo: gerarchia di forme9Progetto: Disegnatore di forme
Panoramica del progettoImplementazione del cerchioImplementazione del rettangoloUtilizzo polimorficoContenitore di formeEsercitati da solo: Compilatore C online