Ein Singleton ist ein objektbasiertes Erzeugermuster und stellt sicher, dass nur ein Exemplar einer Klasse besteht, auf welches global zugegriffen werden kann.
In manchen Fällen kann es wichtig sein, dass nur genau ein Objekt einer Klasse im ganzen Programm existiert. So kann es bspw. in einem System viele Drucker geben, aber nur einen Druckerspooler. Natürlich könnten Sie für einen solchen Fall ein öffentliches Attribute bzw. ein privates Attribut mit entsprechenden Gettern und Settern anlegen. Aber irgendwie müssen Sie von überall (ohne, dass ein bestimmtes Objekt vorhanden ist) auf dieses Attribut zugreifen können. Und wie stellen Sie sicher, dass nicht einfach ein neues Objekt der Klasse erzeugt wird?
Dies funktioniert am Ehesten, wenn eine Klasse selbst ihre eigenen Zugriffsmöglichkeiten steuert. Sie hat einen privaten Konstruktor, so dass von Außen kein neues Objekt von ihr erzeugt werden kann. Außerdem hat sie eine statische, private Instanz von sich selbst. Auf diese Instanz kann über einen entsprechenden, statischen Getter zugegriffen werden. Schon sind die Anforderungen an einen Singleton erfüllt. Machen Sie sich den Sachverhalt nochmals am Diagramm deutlich:

So stellen Sie sicher, dass es genau ein Exemplar einer Klasse gibt, und dass dieses von überall aus erreichbar ist. Seien Sie aber bei der Verwendung von Singletons umsichtig. Es besteht die Gefahr, dass Sie bei exzessiver Verwendung dieses Patterns die Objektorientierung umgehen und aushebeln – was nicht in Ihrem Interesse liegen sollte.
Ansätze
Es gibt zwei Ansätze, um einen Singleton umzusetzen. Mit der Lazy Creation wird das Exemplar erst dann erzeugt, wenn die getInstance-Methode das erste Mal aufgerufen wurde. Wenn kein Objekt benötigt wird, wird auch keine Instanz erzeugt. Bei dieser Variante muss getInstance synchronisiert sein, um die zweimalige Generierung der Instanz durch einen zeitgleichen Zugriff zweier Threads zu unterbinden.
Der andere Ansatz ist die Eager Creation. Hierbei wird die statische Instanz sofort angelegt und nicht erst beim Aufruf der getInstance-Methode. Bei diesem Konzept muss die Zugriffsmethode folglich nicht synchronisiert werden. Meistens ist die Eager Creation der Lazy Creation vorzuziehen, da in Java auch bei der Eager Creation erst das Objekt erzeugt werden würde, wenn das erste Mal auf die Singleton-Klasse zugegriffen wird.
Implementierung
Beide Ansätze setzen ein privates, statisches Attribut der Klasse selbst voraus. Zusätzlich wird ein privater Konstruktor und eine öffentliche, statische Methode getInstance benötigt.
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
return null;
}
}
Bei der Lazy Creation müssen Sie lediglich die getInstance-Methode anpassen. Sie muss synchronisiert sein und testen, ob INSTANCE null ist. Falls dies zutrifft, wird das INSTANCE-Attribute initialisiert und anschließend zurückgegeben.
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public synchronized static Singleton getInstance() {
if (Singleton.INSTANCE == null) {
Singleton.INSTANCE = new Singleton();
}
return Singleton.INSTANCE;
}
}
Die Eager Creation hingegen erfordert eine direkte Initialisierung bei der Deklarierung unserer einzigen Instanz von Singleton. Entsprechend kann das Prozedere in der getInstance-Methode verkürzt werden:
public class Singleton {
private static Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return Singleton.INSTANCE;
}
}
Singleton in Stichpunkten
In diesem Pattern gibt es nur einen Teilnehmer
- Singleton => stellt ein statisches Objekt von sich selbst und eine statische Methode bereit, die es erlaubt, von Außen an die einzige Instanz zu gelangen.
, deren Implementierung bestimmten Grundregeln unterliegt:
- Es darf nur ein Objekt der Singleton-Klasse existieren.
- Dieses Objekt muss global verfügbar gehalten werden.
- Der Zugriff auf dieses Objekt erfolgt ausschließlich über die entsprechende Get-Methode der Singleton-Klasse.
Verwendet wird der Singleton primär, wenn:
- Genau ein Objekt einer Klasse existieren muss, und auf selbiges global zugegriffen werden kann.
Hieraus resultieren gewisse Konsequenzen:
- Die Zugriffskontrolle auf das einzige Objekt dieser Klasse wird von der Klasse selbst gesteuert.
- Ermöglichung einer Art globaler Variablen in Java. (Wobei an dieser Stelle dahingestellt sei, ob dies immer sinnvoll ist.)
- Schnelle Änderung des Konzepts: Sollten Sie doch mehrere Instanzen der Klasse benötigen, genügt es, wenn Sie jedes Mal beim Aufruf von
getInstanceeine neue Instanz der Klasse zurückgeben. Der restliche Code bleibt unberührt.
Kritik am Singleton-Pattern
Mittlerweile sind einige Entwickler und Architekten der Meinung, dass es sich beim Singleton nicht um ein Design-Pattern, sondern um ein Anti-Pattern handelt. Ein Muster, wie man es gerade nicht machen sollte. Dabei wird gerne u. a. auf folgende Kritikpunkte verwiesen:
- Da die Zugriffe durch die globale Verfügbarkeit nicht mehr kontrolliert werden können, wird die Testbarkeit sehr eingeschränkt.
- Verletzung des Single Responsibility Prinzips.
- Ein Singleton wird in den meisten Fällen als „globaler Datenspeicher“ zweckentfremdet. Das eigentliche Ziel, dass es nur ein Objekt der Klasse im ganzen Programm gibt, wird aus den Augen verloren.
- Verschleiern von Abhängigkeiten.
Mit Blick auf den Singleton, sollten Sie noch folgende Pattern beachten, die mit Hilfe eines Singletons implementiert werden könnten:
- Abstract Factory (Abstrakte Fabrik)
- Prototype (Prototyp)
- Builder (Erbauer)
