- 1 Section
- 10 Lessons
- unbegrenzt
Singleton
Das Singleton-Muster ist das bekannteste – und gleichzeitig das umstrittenste – aller Entwurfsmuster. Es gehört zu den Erzeugungsmustern (Creational) und beantwortet eine simple Frage: Wie stelle ich sicher, dass es von einer Klasse genau ein einziges Objekt gibt – und zwar systemweit? Klassisches Beispiel: ein Logger, der in eine Datei schreibt. Wenn jede Code-Stelle ihren eigenen Logger erzeugt, kommt es zu doppelten Dateihandles, vermischten Log-Einträgen, Race-Conditions. Mit Singleton garantieren wir: Logger.getInstance() liefert immer dasselbe Objekt. Diese Lektion zeigt dir, wie es funktioniert, wie es in Java/Python aussieht, welche Tücken es gibt und wann du es nicht einsetzen solltest.
1) Die Idee: „Ein König pro Land"
Eine einfache Analogie macht das Singleton sofort verständlich: in einer Monarchie gibt es zu jedem Zeitpunkt genau einen König oder eine Königin. Wenn jemand fragt „wer ist König von England?", bekommt er immer dieselbe Person als Antwort – egal wer fragt, egal wann. Niemand kann „einfach mal" einen zweiten König krönen. Genauso verhält sich ein Singleton: man kann es nicht mit new erzeugen. Man fragt nach der einen Instanz, und bekommt immer dasselbe Objekt zurück.
Beobachte das in der Simulation. Klick mehrfach „neue Instanz holen" – sowohl bei normaler Klasse als auch beim Singleton. Achte auf die Speicheradresse:
NORMALE Klasse
SINGLETON
0x1A2F, 0x1A5C, ...) – jede Instanz ist ein eigenes Objekt. Beim Singleton ist die Adresse beim ersten Aufruf da, danach bleibt sie identisch. Das ist genau das, was wir wollen: alle Aufrufer arbeiten auf demselben Objekt. Mehr zum Speichermodell in Heap und Stack.2) Singleton in Code – Java und Python
Die Umsetzung folgt einem klaren Bauplan: privater Konstruktor (niemand darf von außen new aufrufen), statisches Attribut für die einzige Instanz, statische Methode getInstance() für den Zugriff. Klick zwischen den Sprachen – die Idee ist gleich, die Syntax unterschiedlich:
getInstance() aufrufen, kann es passieren, dass beide den null-Check passieren und zwei Instanzen erzeugen – die Garantie ist gebrochen. Die thread-safe-Variante verwendet das Double-Checked Locking-Idiom mit volatile. In Python ist das einfacher, weil Klassen-Attribute global einmal existieren und das GIL viele Race-Conditions verhindert. Mehr zur Nebenläufigkeit in Threads & Concurrency.3) Typische Einsatzgebiete
Singleton macht nur Sinn, wenn das Objekt wirklich nur einmal existieren darf oder soll. Klassische Use-Cases:
- Logger: alle Komponenten schreiben in dieselbe Log-Datei. Mehr in Logging und Doku.
- Konfiguration: Anwendungs-Einstellungen werden einmal aus Datei / Umgebung gelesen und sind global verfügbar.
- Datenbank-Connection-Pool: nicht die einzelne Verbindung, sondern der Pool-Manager. Mehr in Connection-Pooling.
- Cache: ein zentraler Cache-Manager, der alle Caches im System koordiniert.
- Hardware-Zugriff: Druckerwarteschlange, serielle Schnittstelle – nur ein Prozess darf zugreifen.
- Event-Bus / Message-Broker (in einer App): alle Komponenten melden sich an dasselbe Bus-Objekt an.
4) Wann Singleton problematisch ist
Singleton ist mächtig – und genau das ist das Problem. Es wird oft als „bequeme globale Variable" missbraucht. Die wichtigsten Kritikpunkte:
| Problem | Warum kritisch |
|---|---|
| Versteckte Abhängigkeit | Wenn Klasse A irgendwo intern Logger.getInstance() aufruft, sieht man das von außen nicht. Schwer zu erkennen, was eine Klasse alles braucht. |
| Test-Probleme | In Unit-Tests kann man Singletons schwer ersetzen / mocken. Tests beeinflussen sich gegenseitig über den geteilten Zustand. |
| Verstößt gegen SRP | Die Klasse macht ihre Hauptaufgabe UND verwaltet ihre Erzeugung. Single-Responsibility wird verletzt. |
| Schwierige Vererbung | Wer erbt von einem Singleton? Wie viele Instanzen darf es geben? Die Garantie wird komplex. |
| Thread-Sicherheit | Naive Implementierung kann zu Race-Conditions führen. Korrekte ist nicht trivial. |
Die moderne Alternative ist Dependency Injection (DI): Anstatt dass die Klasse selbst ein Singleton-Logger holt, bekommt sie einen Logger in den Konstruktor injiziert. Ein DI-Framework wie Spring sorgt dafür, dass es nur eine Logger-Instanz gibt – aber die Klasse selbst muss das nicht wissen. Vorteil: für Tests kann ein Test-Logger reingereicht werden. Mehr in Dependency Injection.
5) Singleton oder nicht – Entscheidungshilfe
In der Prüfung musst du oft beurteilen: Ist Singleton hier angemessen? Drei Szenarien zum Üben:
DBConfig die Datenbank-Verbindungsdaten (Host, User, Passwort) aus einer Konfigurationsdatei laden und allen Komponenten bereitstellen.DBConfig.getInstance() aufrufen – dann ist es testbar.Bestellung für einen Online-Shop. Sie hält Kunde, Produkte, Datum, Gesamtbetrag.CurrentUser, die den gerade angemeldeten Benutzer hält und überall im Code zugreifbar sein soll.CurrentUser würde Benutzer-Sessions vermischen – schwerer Sicherheitsfehler. Stattdessen: per Request-Context (z. B. JWT) den User-Bezug herstellen.6) UML-Darstellung des Singleton
Im UML-Klassendiagramm erkennt man ein Singleton an drei Merkmalen: privater Konstruktor, statisches Attribut der eigenen Klasse, öffentliche statische Methode getInstance(). Statische Elemente werden unterstrichen:
| Singleton | |
|---|---|
| (statische Attribute) – instance: Singleton | |
| (Methoden) – Singleton() (privat!) + getInstance(): Singleton + operation() |
In der Prüfung ist die Erkennung des Singletons an einem UML-Diagramm ein häufiger Aufgabentyp. Achte auf das Minus (privat) am Konstruktor und das Plus (öffentlich) mit Unterstrich (statisch) bei getInstance().
Zusammenfassung
Das Singleton ist ein Erzeugungsmuster, das garantiert: eine Klasse hat genau eine Instanz und bietet einen globalen Zugriffspunkt darauf. Umsetzung: privater Konstruktor + statisches Instanz-Attribut + statische getInstance()-Methode. Einsatzgebiete: Logger, Konfiguration, Cache, Connection-Pool. Achtung: Singleton ist umstritten – versteckt Abhängigkeiten, erschwert Tests, kann Thread-Probleme verursachen. Moderne Alternative: Dependency Injection. In Java braucht thread-sichere Variante volatile + Double-Checked Locking; in Python reicht meist ein Modul-Level-Objekt.
Verwandte Lektionen: Warum Entwurfsmuster? · Factory-Muster · SOLID-Prinzipien · und mehrWeitere relevante LektionenKapselungUML-KlassendiagrammThreads & ConcurrencyRace ConditionsUnit-Tests aufbauenDependency InjectionConnection-Pooling
