Menu
Coddy logo textTech

Padrão Singleton

Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 54 de 61.

Às vezes, você precisa de exatamente uma instância de um objeto em todo o seu programa: um gerenciador de configuração, um sistema de registro ou uma conexão com o banco de dados. O padrão Singleton garante que apenas uma instância exista e fornece um ponto de acesso global a ela.

Em C, implementamos isso usando uma variável static dentro de um arquivo-fonte. Lembre-se de que static no escopo do arquivo significa que a variável é privada para esse arquivo e persiste durante toda a vida útil do programa. Combinado com uma função getter, isso cria nosso 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;
}

A mágica acontece em get_config(). A primeira chamada cria e inicializa a instância. Cada chamada subsequente retorna o mesmo ponteiro.

A palavra-chave static garante que instance retenha seu valor entre chamadas de função e permaneça oculta de outros arquivos.

Do cabeçalho, os usuários veem apenas a função getter. Eles não podem acessar nem modificar a variável estática diretamente. Não importa quantas vezes ou de onde você chama get_config(), você sempre obtém o mesmo objeto.

challenge icon

Desafio

Fácil

Vamos criar um módulo Settings que gerencia a configuração de toda a aplicação usando o padrão Singleton. Não importa quantas vezes seu código solicite as configurações, ele deverá sempre receber exatamente a mesma instância.

Você organizará seu código em três arquivos:

  • settings.h: Declare um tipo opaco Settings usando uma declaração antecipada (o corpo da estrutura permanece oculto). Declare uma função get_settings que retorna um ponteiro para a instância Singleton, além de funções getter e setter para dois valores de configuração: volume (um inteiro) e brightness (um inteiro). As proteções contra inclusão múltipla são essenciais aqui.
  • settings.c: É aqui que a mágica acontece. Defina a estrutura Settings real com os campos volume e brightness. Crie uma variável ponteiro static para armazenar a única instância (inicializada como NULL). Implemente get_settings de modo que a primeira chamada aloque e inicialize a instância com valores padrão (volume: 50, brilho: 75), enquanto as chamadas subsequentes simplesmente retornem a instância existente. Implemente os getters e setters para acessar e modificar os campos ocultos.
  • main.c: Demonstre que o Singleton funciona corretamente. Leia dois inteiros que representam novos valores de volume e brilho. Chame get_settings duas vezes, armazenando os resultados em duas variáveis ponteiro diferentes. Use o primeiro ponteiro para atualizar o volume e o brilho com os valores de entrada. Em seguida, use o segundo ponteiro para recuperar e imprimir os dois valores. Se o Singleton estiver funcionando, as alterações feitas por meio de um ponteiro estarão visíveis por meio do outro.

Seu programa receberá duas entradas:

  1. O novo valor do volume
  2. O novo valor do brilho

Imprima o volume e o brilho em linhas separadas depois de modificá-los por meio de um ponteiro e lê-los por meio de outro.

Exemplo de saída quando as entradas são 80 e 100:

80
100

Exemplo de saída quando as entradas são 25 e 60:

25
60

Exemplo de saída quando as entradas são 0 e 50:

0
50

A ideia principal é que ambos os ponteiros apontam para o mesmo objeto na memória: essa é a essência do padrão Singleton. A variável estática dentro do seu arquivo de código-fonte garante que apenas uma instância exista, e ela persiste durante toda a vida útil do programa.

Experimente você mesmo

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

int main() {
    int new_volume, new_brightness;
    scanf("%d", &new_volume);
    scanf("%d", &new_brightness);
    
    // TODO: Chame get_settings duas vezes e armazene em duas variáveis de ponteiro diferentes
    
    
    // TODO: Use o primeiro ponteiro para atualizar volume e brightness com os valores de entrada
    
    
    // TODO: Use o segundo ponteiro para recuperar e imprimir volume e brightness
    // (Isso demonstra que ambos os ponteiros apontam para a mesma instância singleton)
    
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de C online