Menu
Coddy logo textTech

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.

challenge icon

Sfida

Facile

Creiamo 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 tipo Settings opaco usando una dichiarazione anticipata (il corpo della struct rimane nascosto). Dichiara una funzione get_settings che restituisce un puntatore all'istanza singleton, oltre a funzioni getter e setter per due valori di configurazione: volume (un intero) e brightness (un intero). Le protezioni contro le inclusioni multiple sono essenziali.
  • settings.c: è qui che avviene la magia. Definisci la struct Settings effettiva con i campi volume e brightness. Crea una variabile puntatore static che contenga l'unica istanza (inizializzata a NULL). Implementa get_settings in 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à. Chiama get_settings due 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:

  1. Il nuovo valore del volume
  2. 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
100

Esempio di output quando gli input sono 25 e 60:

25
60

Esempio di output quando gli input sono 0 e 50:

0
50

L'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;
}
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore C online