Menu
Coddy logo textTech

Wzorzec Singleton

Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 54 z 61.

Czasami w całym programie potrzebujesz dokładnie jednej instancji obiektu: menedżera konfiguracji, systemu logowania lub połączenia z bazą danych. Wzorzec Singleton gwarantuje, że istnieje tylko jedna instancja, i zapewnia globalny punkt dostępu do niej.

W języku C implementujemy to za pomocą zmiennej static wewnątrz pliku źródłowego. Pamiętaj, że static na poziomie pliku oznacza, że zmienna jest prywatna dla tego pliku i istnieje przez cały czas działania programu. W połączeniu z funkcją pobierającą tworzy to nasz 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;
}

Magia dzieje się w get_config(). Pierwsze wywołanie tworzy i inicjalizuje instancję. Każde kolejne wywołanie zwraca ten sam wskaźnik.

Słowo kluczowe static sprawia, że instance zachowuje swoją wartość między wywołaniami funkcji i pozostaje ukryte przed innymi plikami.

Z nagłówka użytkownicy widzą tylko funkcję pobierającą. Nie mogą bezpośrednio uzyskiwać dostępu do zmiennej statycznej ani jej modyfikować. Bez względu na to, ile razy i z jakiego miejsca wywołasz get_config(), zawsze otrzymasz ten sam obiekt.

challenge icon

Wyzwanie

Łatwy

Zbudujmy moduł Settings, który zarządza konfiguracją całej aplikacji za pomocą wzorca Singleton. Niezależnie od tego, ile razy kod poprosi o ustawienia, zawsze powinien otrzymać dokładnie tę samą instancję.

Rozmieścisz kod w trzech plikach:

  • settings.h: Zadeklaruj nieprzezroczysty typ Settings za pomocą deklaracji wstępnej (definicja struktury pozostaje ukryta). Zadeklaruj funkcję get_settings, która zwraca wskaźnik do instancji Singletona, a także funkcje pobierające i ustawiające dwie wartości konfiguracyjne: volume (liczba całkowita) i brightness (liczba całkowita). W tym przypadku strażniki dołączania są niezbędne.
  • settings.c: Tutaj dzieje się cała magia. Zdefiniuj właściwą strukturę Settings z polami volume i brightness. Utwórz zmienną wskaźnikową static, która będzie przechowywać pojedynczą instancję (zainicjalizowaną jako NULL). Zaimplementuj get_settings tak, aby pierwsze wywołanie alokowało i inicjalizowało instancję wartościami domyślnymi (volume: 50, brightness: 75), a kolejne wywołania po prostu zwracały istniejącą instancję. Zaimplementuj funkcje pobierające i ustawiające, aby umożliwić dostęp do ukrytych pól i ich modyfikację.
  • main.c: Zademonstruj, że Singleton działa poprawnie. Wczytaj dwie liczby całkowite reprezentujące nowe wartości volume i brightness. Wywołaj dwukrotnie get_settings, zapisując wyniki w dwóch różnych zmiennych wskaźnikowych. Użyj pierwszego wskaźnika, aby zaktualizować volume i brightness wartościami wejściowymi. Następnie użyj drugiego wskaźnika, aby pobrać i wypisać obie wartości. Jeśli Singleton działa poprawnie, zmiany wprowadzone za pomocą jednego wskaźnika będą widoczne za pomocą drugiego.

Program otrzyma dwa wejścia:

  1. Nową wartość volume
  2. Nową wartość brightness

Po ich zmodyfikowaniu za pomocą jednego wskaźnika i odczytaniu za pomocą drugiego wypisz volume i brightness w osobnych wierszach.

Przykładowe wyjście dla wejść 80 i 100:

80
100

Przykładowe wyjście dla wejść 25 i 60:

25
60

Przykładowe wyjście dla wejść 0 i 50:

0
50

Najważniejsze jest to, że oba wskaźniki wskazują ten sam obiekt w pamięci — na tym polega istota wzorca Singleton. Zmienna statyczna w pliku źródłowym gwarantuje, że istnieje tylko jedna instancja, która pozostaje dostępna przez cały czas działania programu.

Spróbuj swoich sił

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

int main() {
    int new_volume, new_brightness;
    scanf("%d", &new_volume);
    scanf("%d", &new_brightness);
    
    // TODO: Wywołaj get_settings dwukrotnie i zapisz wyniki w dwóch różnych zmiennych wskaźnikowych
    
    
    // TODO: Użyj pierwszego wskaźnika, aby zaktualizować głośność i jasność wartościami wejściowymi
    
    
    // TODO: Użyj drugiego wskaźnika, aby odczytać i wyświetlić głośność oraz jasność
    // (To pokazuje, że oba wskaźniki wskazują na tę samą instancję singletonu)
    
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C online