Menu
Coddy logo textTech

Patrón Singleton

Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 54 de 61.

A veces necesitas exactamente una instancia de un objeto en todo tu programa: un gestor de configuración, un sistema de registro o una conexión a una base de datos. El patrón Singleton garantiza que solo exista una instancia y proporciona un punto de acceso global a ella.

En C, implementamos esto usando una variable static dentro de un archivo fuente. Recuerda que static en el ámbito del archivo significa que la variable es privada para ese archivo y persiste durante toda la vida del programa. Combinado con una función getter, esto crea nuestro 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 ocurre en get_config(). La primera llamada crea e inicializa la instancia. Cada llamada posterior devuelve el mismo puntero.

La palabra clave static asegura que instance conserve su valor entre llamadas a funciones y permanezca oculta para otros archivos.

Desde el encabezado, los usuarios solo ven la función getter; no pueden acceder ni modificar la variable estática directamente. No importa cuántas veces o desde dónde llames a get_config(), siempre obtendrás el mismo objeto.

challenge icon

Desafío

Fácil

Vamos a construir un módulo Settings que gestione la configuración de toda la aplicación utilizando el patrón Singleton. No importa cuántas veces tu código solicite la configuración, siempre debe recibir exactamente la misma instancia.

Organizarás tu código en tres archivos:

  • settings.h: Declara un tipo Settings opaco utilizando una declaración anticipada (el cuerpo de la estructura permanece oculto). Declara una función get_settings que devuelva un puntero a la instancia singleton, además de funciones getter y setter para dos valores de configuración: volume (un entero) y brightness (un entero). Los protectores de inclusión (include guards) son esenciales aquí.
  • settings.c: Aquí es donde ocurre la magia. Define la estructura Settings real con los campos volume y brightness. Crea una variable de puntero static para mantener la instancia única (inicializada en NULL). Implementa get_settings de modo que la primera llamada asigne e inicialice la instancia con valores predeterminados (volume: 50, brightness: 75), mientras que las llamadas posteriores simplemente devuelvan la instancia existente. Implementa los getters y setters para acceder y modificar los campos ocultos.
  • main.c: Demuestra que el Singleton funciona correctamente. Lee dos enteros que representen los nuevos valores de volumen y brillo. Llama a get_settings dos veces, almacenando los resultados en dos variables de puntero diferentes. Usa el primer puntero para actualizar el volumen y el brillo con los valores de entrada. Luego, usa el segundo puntero para recuperar e imprimir ambos valores. Si el Singleton está funcionando, los cambios realizados a través de un puntero serán visibles a través del otro.

Tu programa recibirá dos entradas:

  1. El nuevo valor de volumen
  2. El nuevo valor de brillo

Imprime el volumen y el brillo en líneas separadas después de modificarlos a través de un puntero y leerlos a través de otro.

Ejemplo de salida cuando las entradas son 80 y 100:

80
100

Ejemplo de salida cuando las entradas son 25 y 60:

25
60

Ejemplo de salida cuando las entradas son 0 y 50:

0
50

La idea clave es que ambos punteros apuntan al mismo objeto en la memoria; esa es la esencia del patrón Singleton. La variable estática dentro de tu archivo fuente asegura que solo exista una instancia, y esta persiste durante toda la vida del programa.

Hoja de referencia

El patrón Singleton asegura que solo exista una instancia de un objeto en todo el programa y proporciona un punto de acceso global a ella.

En C, implemente un Singleton utilizando una variable static dentro de un archivo fuente combinada con una función 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;
}

Puntos clave:

  • La palabra clave static a nivel de archivo hace que la variable sea privada para ese archivo y persistente durante la vida útil del programa
  • La función getter comprueba si la instancia es NULL en la primera llamada, la crea e inicializa, y luego la devuelve
  • Las llamadas posteriores devuelven el mismo puntero
  • Los usuarios solo ven la función getter a través del encabezado — no pueden acceder ni modificar la variable estática directamente
  • No importa cuántas veces o desde dónde llame al getter, siempre obtendrá el mismo objeto

Pruébalo tú mismo

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

int main() {
    int new_volume, new_brightness;
    scanf("%d", &new_volume);
    scanf("%d", &new_brightness);
    
    // TODO: Llama a get_settings dos veces y almacena el resultado en dos variables de puntero diferentes
    
    
    // TODO: Usa el primer puntero para actualizar volume y brightness con los valores de entrada
    
    
    // TODO: Usa el segundo puntero para recuperar e imprimir volume y brightness
    // (Esto demuestra que ambos punteros apuntan a la misma instancia singleton)
    
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming