Muster: Singleton
Zweck und Verwendung
[Bearbeiten]Das Einzelstück wird benutzt, um genau eine Instanz einer Klasse und einen zentralen Zugriffspunkt auf diese Instanz bereitzustellen. Dies ist sinnvoll, wenn nur ein Objekt gebraucht wird, um Aktionen im System auszuführen. Bisweilen muss verhindert werden, dass von einer Klasse mehr als eine Instanz erzeugt werden kann - genau dies leistet das Singleton-Muster.
Zum Beispiel kann eine zentrale Konfigurationsklasse als Einzelstück implementiert werden. Dies ist eine aus objektorientierter Sicht sauberere Umsetzung als beispielsweise eine Umsetzung mittels globalen Variablen. (siehe Kapitel Vorteile)
UML
[Bearbeiten]Anwendungsfälle
[Bearbeiten]Ein Beispiel für solch einen Fall ist eine Klasse, die die Verbindung zu einer Datenbank verwaltet und für den Rest des Programms Funktionen zur Verfügung stellt, um auf die Datenbank zuzugreifen. Angenommen die Datenbank bietet selbst keine Mechanismen, um beispielsweise atomare Operationen zu gewährleisten; dies bleibt dann der Datenbankklasse vorbehalten. Gäbe es nun mehrere Instanzen dieser Datenbank-Klasse, könnten wiederum verschiedene Teile des Programms gleichzeitig Änderungen an der Datenbank vornehmen, indem sie sich unterschiedlicher Instanzen bedienen. Wenn es allerdings nur genau ein Exemplar der Datenbank-Klasse gibt, tritt dieses Problem nicht auf.
Die GoF-Muster Abstract-Factory, Builder und Prototype können Singleton in ihrer Implementierung verwenden.
Vorteile
[Bearbeiten]- Die Einzelinstanz muss nur erzeugt werden, wenn sie benötigt wird.
- Die Einzelinstanz wird erst zu dem Zeitpunkt erzeugt, zu dem sie benötigt wird (Lazy loading)
- Der Zugriff auf das Einzelstück ist leichter handhabbar, wenn diese als globale Klassenvariable in jeder Klasse (inklusive den Zuweisungen des Objektes an diese Variablen) implementiert werden muss.
- Zugriffskontrolle kann realisiert werden.
- Das Singleton kann durch Unterklassenbildung spezialisiert werden.
- Welche Unterklasse verwendet werden soll, kann zur Laufzeit entschieden werden.
- Sollten später mehrere Objekte benötigt werden, ist eine Änderung leichter möglich als bei globalen Variablen.
Nachteile
[Bearbeiten]Diese Inhalte stammen aus der deutschen Wikipedia. Ein Abgleich mit gängiger Literatur folgt.
- Es besteht die große Gefahr, durch exzessive Verwendung von Singletons quasi ein Äquivalent zu globalen Variablen zu implementieren und damit dann prozedural anstatt objektorientiert zu programmieren.
- Abhängigkeiten zur Singleton-Klasse werden verschleiert, d. h. ob eine Singleton-Klasse verwendet wird, erschließt sich nicht aus dem Interface einer Klasse, sondern nur anhand der Implementierung. Zudem wird die Kopplung erhöht, was Wiederverwendbarkeit und Übersichtlichkeit einschränkt.
- Fehler erzeugt werden sollen – fast unmöglich. Mit der Java Reflection API ist es jedoch möglich, die Kapselung der Singleton zu verletzen und die Instanziierung zu kontrollieren.
- Die Konfiguration des Singletons ist – zumindest bei Lazy-Initialization (s. u.) – nur über andere Singletons möglich, zum Beispiel Environment-Variablen, aus einem Registry, aus „well-known“ Files o. Ä.
Entscheidungshilfen
[Bearbeiten]Ein Singleton sollte dann eingesetzt werden, wenn sichergestellt sein muss, dass nicht mehr als ein Objekt einer Klasse erzeugt werden kann. Dabei ist jedoch genau zu überlegen, worauf sich "ein Objekt" bezieht: Pro Programm? Bei ge-cluster-ten Anwendungen: pro Cluster? Bei Java-Programmen: pro ClassLoader?
Singletons sind das semantische Äquivalent einer globalen Variablen, mit all der damit verbundenen Problematik; es ist genau zu überlegen, ob das jeweilige Ziel nicht anders besser erreicht werden kann.
Implementation
[Bearbeiten]Anstatt selbst eine neue Instanz durch Aufruf des Konstruktors zu erzeugen, müssen sich Benutzer der Singleton-Klasse eine Referenz auf eine Instanz über die statische getInstance()
-Methode besorgen - die Singleton-Klasse ist also selbst für die Verwaltung ihrer einzigen Instanz zuständig. Die getInstance()
-Methode kann nun sicherstellen, dass bei jedem Aufruf eine Referenz auf dieselbe und einzige Instanz - gehalten in einer (versteckten) Klassenvariable - zurückgegeben wird. Üblicherweise wird diese eine Instanz von getInstance()
beim ersten Aufruf erzeugt.
In nebenläufigen Programmen muss der Programmierer beim Schreiben der getInstance()
-Methode besondere Vorsicht walten lassen (siehe Code-Beispiele).
Bei der Implementierung zu beachten:
- In Multithreaded-Umgebungen können Fehler passieren, wenn konkurrierende Threads gleichzeitig Singletons erzeugen. Die Erzeugungsmethode darf also nur von einem Thread gleichzeitig (also exklusiv) ausgeführt werden können.
- Eine Ressourcen-Deallokation von Ressourcen, die das Singleton verwendet, ist schwierig. So ist zum Beispiel bei einem Singleton für ein Logging-System oft unklar, wann die Logdatei geschlossen werden soll. Dies ist beim Design der Anwendung zu bedenken.
Beispiele
[Bearbeiten]Konkrete Implementationen für die Programmiersprachen
- C++,
- C#,
- Java,
- Java mit Multithreading und
- PHP
Verwandte Muster
[Bearbeiten]- Fabrikmuster, da das Singleton üblicherweise eine Klassenfabrik für genau eine Instanz der eigenen Klasse darstellt