Menu
Coddy logo textTech

Singleton-Muster

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 91 von 104.

Das Singleton-Muster stellt sicher, dass eine Klasse während des gesamten Programms nur eine Instanz besitzt, und bietet einen globalen Zugriffspunkt darauf. Dies ist nützlich für Ressourcen, die gemeinsam genutzt werden sollten, wie etwa einen Konfigurationsmanager, Logger oder Datenbankverbindungspool.

Die zentrale Idee besteht darin, den Konstruktor privat zu machen, sodass niemand direkt Instanzen erstellen kann, und anschließend eine statische Methode bereitzustellen, die die einzelne Instanz zurückgibt:

#include <iostream>
#include <string>

class Logger {
private:
    std::string logFile;
    
    // Privater Konstruktor – verhindert direkte Instanziierung
    Logger() : logFile("app.log") {}
    
    // Copy-Konstruktor und Zuweisungsoperator löschen
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

public:
    // Statische Methode zum Zugriff auf die einzige Instanz
    static Logger& getInstance() {
        static Logger instance;  // Wird einmal erstellt, lebt bis zum Programmende
        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");
}

Das static Logger instance innerhalb von getInstance() ist ein C++11-Feature namens „Magic Statics“ – es ist threadsicher und wird garantiert nur einmal initialisiert. Indem wir den Kopierkonstruktor und den Zuweisungsoperator löschen, verhindern wir, dass jemand Kopien unseres Singletons erstellt.

Verwende Singleton sparsam – es führt einen globalen Zustand ein, der das Testen erschweren kann. Es eignet sich am besten für wirklich gemeinsam genutzte Ressourcen, bei denen mehrere Instanzen Probleme verursachen würden.

challenge icon

Aufgabe

Einfach

Erstellen wir ein GameSettings-Singleton, das die Konfiguration für eine Spieleanwendung verwaltet. Dies ist ein perfekter Anwendungsfall für das Singleton-Muster. Du möchtest genau einen Einstellungsmanager, auf den alle Teile deines Spiels zugreifen können, um eine konsistente Konfiguration im gesamten Spiel sicherzustellen.

Du organisierst deinen Code auf drei Dateien verteilt:

  • GameSettings.h: Definiere deine Singleton-Klasse, die die Spielkonfiguration verwaltet.

    Deine Klasse GameSettings sollte drei Einstellungen als private Member speichern: difficulty (String), volume (Ganzzahl von 0–100) und fullscreen (boolescher Wert). Initialisiere sie mit den Standardwerten: "Normal", 50 und false.

    Implementiere das Singleton-Muster korrekt:

    • Der Konstruktor muss private sein
    • Lösche den Kopierkonstruktor und den Zuweisungsoperator
    • Stelle eine statische Methode getInstance() bereit, die eine Referenz auf die einzige Instanz zurückgibt

    Füge diese öffentlichen Methoden hinzu, um mit den Einstellungen zu interagieren:

    • setDifficulty(const std::string& diff): aktualisiert den Schwierigkeitsgrad
    • setVolume(int vol): aktualisiert die Lautstärke
    • setFullscreen(bool fs): aktualisiert den Vollbildmodus
    • displaySettings(): gibt alle aktuellen Einstellungen aus
  • GameModule.h: Erstelle ein separates Modul, das auf das Singleton zugreift.

    Definiere eine Funktion namens applyGamePreset, die einen Preset-Namen (String) entgegennimmt. Diese Funktion sollte auf das GameSettings-Singleton zugreifen und es abhängig vom Preset konfigurieren:

    • "casual": setzt den Schwierigkeitsgrad auf "Easy", die Lautstärke auf 70 und den Vollbildmodus auf false
    • "competitive": setzt den Schwierigkeitsgrad auf "Hard", die Lautstärke auf 30 und den Vollbildmodus auf true
    • Jedes andere Preset: behält die Standardeinstellungen unverändert bei

    Dies zeigt, wie verschiedene Teile eines Programms auf dieselbe Singleton-Instanz zugreifen und sie ändern können.

  • main.cpp: Führe alles zusammen, um das Singleton in Aktion zu zeigen.

    Lies zwei Eingaben ein:

    1. Einen Preset-Namen (String)
    2. Einen benutzerdefinierten Lautstärkepegel (Ganzzahl)

    Gib zuerst die anfänglichen Standardeinstellungen aus, indem du displaySettings() für das Singleton aufrufst. Gib danach eine Leerzeile aus.

    Wende anschließend das Preset mit deiner Funktion applyGamePreset an und gib die Einstellungen erneut aus. Gib danach eine Leerzeile aus.

    Überschreibe schließlich nur die Lautstärke mit dem benutzerdefinierten Eingabewert und gib die endgültigen Einstellungen aus.

Die Methode displaySettings() sollte exakt in diesem Format ausgeben:

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

Zum Beispiel mit den Eingaben casual und 85:

Difficulty: Normal
Volume: 50
Fullscreen: no

Difficulty: Easy
Volume: 70
Fullscreen: no

Difficulty: Easy
Volume: 85
Fullscreen: no

Mit den Eingaben competitive und 20:

Difficulty: Normal
Volume: 50
Fullscreen: no

Difficulty: Hard
Volume: 30
Fullscreen: yes

Difficulty: Hard
Volume: 20
Fullscreen: yes

Beachte, wie sowohl main.cpp als auch GameModule.h auf dieselbe Singleton-Instanz zugreifen: Änderungen, die an einer Stelle vorgenommen werden, sind überall sichtbar. Das ist die Stärke des Singleton-Musters für gemeinsam genutzte Ressourcen wie Spieleinstellungen.

Probier es selbst

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

using namespace std;

int main() {
    // Eingaben lesen
    string presetName;
    int customVolume;
    cin >> presetName;
    cin >> customVolume;
    
    // TODO: Hole die GameSettings-Singleton-Instanz
    
    // TODO: Zeige die anfänglichen Standardeinstellungen an
    
    // TODO: Gib eine leere Zeile aus
    
    // TODO: Wende das Preset mit der Funktion applyGamePreset an
    
    // TODO: Zeige die Einstellungen nach dem Anwenden des Presets an
    
    // TODO: Gib eine leere Zeile aus
    
    // TODO: Überschreibe die Lautstärke mit customVolume
    
    // TODO: Zeige die endgültigen Einstellungen an
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler