Menu
Coddy logo textTech

Patrón Singleton

Parte de la sección Programación Orientada a Objetos 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 útil 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 garantiza que instance conserve su valor entre llamadas a funciones y permanezca oculta para otros archivos.

Desde el archivo de cabecera, los usuarios solo ven la función getter. No pueden acceder directamente a la variable estática ni modificarla. Sin importar cuántas veces ni desde dónde llames a get_config(), siempre obtienes el mismo objeto.

challenge icon

Desafío

Fácil

Construyamos un módulo Settings que gestione la configuración de toda la aplicación mediante el patrón Singleton. Sin importar cuántas veces tu código solicite la configuración, siempre debería recibir exactamente la misma instancia.

Organizarás tu código en tres archivos:

  • settings.h: Declara un tipo opaco Settings mediante 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). Las guardas de inclusión 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 puntero static para almacenar la única instancia (inicializada en NULL). Implementa get_settings de modo que la primera llamada asigne memoria 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 a los campos ocultos y modificarlos.
  • main.c: Demuestra que el Singleton funciona correctamente. Lee dos enteros que representan nuevos valores de volume y brightness. Llama dos veces a get_settings, almacenando los resultados en dos variables puntero diferentes. Usa el primer puntero para actualizar volume y brightness con los valores de entrada. Después, usa el segundo puntero para recuperar e imprimir ambos valores. Si el Singleton funciona, los cambios realizados mediante un puntero serán visibles a través del otro.

Tu programa recibirá dos entradas:

  1. El nuevo valor de volume
  2. El nuevo valor de brightness

Imprime volume y brightness en líneas separadas después de modificarlos mediante un puntero y leerlos mediante otro.

Salida de ejemplo cuando las entradas son 80 y 100:

80
100

Salida de ejemplo cuando las entradas son 25 y 60:

25
60

Salida de ejemplo cuando las entradas son 0 y 50:

0
50

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

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 en dos variables 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 Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C online