Menu
Coddy logo textTech

Wzorzec Singleton

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 91 z 104.

Wzorzec Singleton gwarantuje, że klasa ma tylko jedną instancję w całym programie, i zapewnia globalny punkt dostępu do niej. Jest to przydatne w przypadku zasobów, które powinny być współdzielone, takich jak menedżer konfiguracji, rejestrator lub pula połączeń z bazą danych.

Kluczową ideą jest ustawienie konstruktora jako prywatnego, aby nikt nie mógł bezpośrednio tworzyć instancji, a następnie udostępnienie metody statycznej, która zwraca jedyną instancję:

#include <iostream>
#include <string>

class Logger {
private:
    std::string logFile;
    
    // Prywatny konstruktor – uniemożliwia bezpośrednie tworzenie instancji
    Logger() : logFile("app.log") {}
    
    // Usuń konstruktor kopiujący i operator przypisania
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

public:
    // Metoda statyczna zapewniająca dostęp do jedynej instancji
    static Logger& getInstance() {
        static Logger instance;  // Tworzona tylko raz, istnieje do końca działania programu
        return instance;
    }
    
    void log(const std::string& message) {
        std::cout << "[LOG] " << message << "\n";
    }
};

int main() {
    Logger::getInstance().log("Application started");
    
    Logger& logger = Logger::getInstance();
    logger.log("Processing data");
}

static Logger instance wewnątrz getInstance() to funkcja języka C++11 zwana „magic statics” — jest bezpieczna wątkowo i gwarantuje, że zostanie zainicjalizowana tylko raz. Usuwając konstruktor kopiujący i operator przypisania, uniemożliwiamy tworzenie kopii naszego singletona.

Używaj wzorca Singleton oszczędnie — wprowadza stan globalny, który może utrudnić testowanie. Najlepiej sprawdza się w przypadku rzeczywiście współdzielonych zasobów, dla których wiele instancji mogłoby powodować problemy.

challenge icon

Wyzwanie

Łatwy

Zbudujmy singleton GameSettings, który zarządza konfiguracją aplikacji gry. To idealny przypadek użycia wzorca Singleton. Chcesz mieć dokładnie jednego menedżera ustawień, do którego mają dostęp wszystkie części gry, co zapewnia spójną konfigurację w całej aplikacji.

Rozmieścisz kod w trzech plikach:

  • GameSettings.h: Zdefiniuj klasę singletona, która zarządza konfiguracją gry.

    Klasa GameSettings powinna przechowywać trzy ustawienia jako prywatne składowe: difficulty (ciąg znaków), volume (liczba całkowita z zakresu 0-100) oraz fullscreen (wartość logiczna). Zainicjuj je wartościami domyślnymi: "Normal", 50 i false.

    Zaimplementuj poprawnie wzorzec Singleton:

    • Ustaw konstruktor jako prywatny
    • Usuń konstruktor kopiujący i operator przypisania
    • Udostępnij statyczną metodę getInstance(), która zwraca referencję do jedynej instancji

    Dodaj następujące publiczne metody do obsługi ustawień:

    • setDifficulty(const std::string& diff): aktualizuje poziom trudności
    • setVolume(int vol): aktualizuje głośność
    • setFullscreen(bool fs): aktualizuje tryb pełnoekranowy
    • displaySettings(): wyświetla wszystkie bieżące ustawienia
  • GameModule.h: Utwórz osobny moduł, który korzysta z singletona.

    Zdefiniuj funkcję o nazwie applyGamePreset, która przyjmuje nazwę ustawienia wstępnego (ciąg znaków). Ta funkcja powinna uzyskać dostęp do singletona GameSettings i skonfigurować go na podstawie ustawienia wstępnego:

    • "casual": ustawia poziom trudności na "Easy", głośność na 70, a tryb pełnoekranowy na false
    • "competitive": ustawia poziom trudności na "Hard", głośność na 30, a tryb pełnoekranowy na true
    • Każde inne ustawienie wstępne: pozostawia ustawienia domyślne bez zmian

    To pokazuje, jak różne części programu mogą uzyskiwać dostęp do tej samej instancji singletona i ją modyfikować.

  • main.cpp: Połącz wszystkie elementy, aby pokazać singletona w działaniu.

    Wczytaj dwa dane wejściowe:

    1. Nazwę ustawienia wstępnego (ciąg znaków)
    2. Niestandardowy poziom głośności (liczba całkowita)

    Najpierw wyświetl początkowe ustawienia domyślne, wywołując metodę displaySettings() singletona. Następnie wypisz pusty wiersz.

    Potem zastosuj ustawienie wstępne za pomocą funkcji applyGamePreset i ponownie wyświetl ustawienia. Następnie wypisz pusty wiersz.

    Na koniec zastąp tylko wartość głośności wartością wczytaną z danych wejściowych i wyświetl ustawienia końcowe.

Metoda displaySettings() powinna wyświetlać dane dokładnie w tym formacie:

Difficulty: [value]
Volume: [value]
Fullscreen: [yes/no]

Na przykład dla danych wejściowych casual i 85:

Difficulty: Normal
Volume: 50
Fullscreen: no

Difficulty: Easy
Volume: 70
Fullscreen: no

Difficulty: Easy
Volume: 85
Fullscreen: no

Dla danych wejściowych competitive i 20:

Difficulty: Normal
Volume: 50
Fullscreen: no

Difficulty: Hard
Volume: 30
Fullscreen: yes

Difficulty: Hard
Volume: 20
Fullscreen: yes

Zwróć uwagę, że zarówno main.cpp, jak i GameModule.h uzyskują dostęp do tej samej instancji singletona: zmiany wprowadzone w jednym miejscu są widoczne wszędzie. Na tym polega siła wzorca Singleton w przypadku współdzielonych zasobów, takich jak ustawienia gry.

Spróbuj swoich sił

#include <iostream>
#include <string>
#include "GameSettings.h"
#include "GameModule.h"

using namespace std;

int main() {
    // Odczytaj dane wejściowe
    string presetName;
    int customVolume;
    cin >> presetName;
    cin >> customVolume;
    
    // TODO: Pobierz instancję singletonu GameSettings
    
    // TODO: Wyświetl początkowe ustawienia domyślne
    
    // TODO: Wypisz pusty wiersz
    
    // TODO: Zastosuj ustawienia wstępne za pomocą funkcji applyGamePreset
    
    // TODO: Wyświetl ustawienia po zastosowaniu ustawień wstępnych
    
    // TODO: Wypisz pusty wiersz
    
    // TODO: Zastąp poziom głośności wartością customVolume
    
    // TODO: Wyświetl ustawienia końcowe
    
    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