Es ist wieder einmal an der Zeit ein einfaches Pattern genauer zu durchleuchten. Das Singleton Pattern… Ich denke, es ist eines der einfachsten Pattern überhaupt und nur die wenigsten denken darüber nach, wann man es braucht oder ob man es überhaupt verwendet.

Wenn man in einer Anwendung eine Klasse benötigt, die nur genau einmal instanziert werden soll, kann man dieses Pattern verwenden. Ich schreibe absichtlich „kann“, weil es ja auch noch andere Möglichkeiten gibt, aber dazu komme ich später. Was gibt es zum Beispiel für Beispiele, wann man eine Klasse nur einmal innerhalb einer Anwendung instanzieren will? Da wäre zum Beispiel der Aufbau einer Datenbank-Verbindung. Im Idealfall baut man nur eine Datenbankverbindung auf und verwendet diese Connection dann von unterschiedlichen Stellen aus. Oder ein bisschen versteckter: Wenn man Inversion of Control verwendet, wird im Normalfall nur jeweils eine Instanz der zu liefernden Objekte erstellt.

So. Wie funktioniert jetzt dieses Pattern? Ich versuche es erst einmal in Worten zu beschreiben: Man braucht eine zentrale Stelle, die eine Instanz eines Objekts erstellt und bei Bedarf immer diese eine erstellte Instanz zurückliefert, mit der man dann arbeiten kann. Zusätzlich muss sicher gestellt werden, dass man keine andere Möglichkeit hat eine entsprechende Instanz zu erzeugen. Man brauch also einen privaten Konstruktor, den man von außen nicht aufrufen kann. Das bedeutet dann automatisch, dass das Erstellen des Objekts im Objekt selbst erfolgen muss. Die einzige Möglichkeit, die man dazu hat ist eine statische Methode innerhalb der Klasse, die man erstellen will. Das war’s im Prinzip auch schon.

Hier mal ein bisschen Code, wie das aussehen kann:

public class SingletonClass
{
    private static SingletonClass _instance;
    public static SingletonClass Instance
    {
        get
        {
            if (_instance == null)
                _instance = new SingletonClass();
            return _instance;
        }
    }

    private SingletonClass() { }

    public void DoSomething()
    {
        ...
    }
}

Der Aufruf würde dann folgendermaßen aussehen:

SingletonClass.Instance.DoSomething();

Wie man sieht, ist das wirklich ganz einfach zu bewerkstelligen. Beim Aufruf der statischen Property „Instance“ wird überprüft, ob es bereits eine Instanz des Objekts gibt. Wenn nicht, wird eine Instanz erstellt und dann wird diese eine Instanz zurück gegeben. Mit der erzeugten Instanz kann man dann beliebig arbeiten.

Der größte Vorteil liegt hier klar auf der Hand. Durch die Verwendung der Property „Instanz“ kann es nur eine Instant dieser Klasse geben. Außer… Natürlich gibt es immer wieder Problemfälle bei denen das nicht funktioniert. Nehmen wir an, wir haben eine Anwendung mit mehreren Threads. Dann kann es vorkommen, dass zwei Threads gleichzeitig abprüfen, ob eine Instanz besteht und beide versuchen dann, eine Instanz zu erzeugen. Es kann ja auch manchmal ein bisschen länger dauern, bis die Instanz eines Objekts erzeugt ist und solange der Konstruktor nicht durchgelaufen ist, ist die Variable _instance immer noch null. Damit dies nicht passiert, muss man einen entsprechenden Lock-Mechanismus einbauen.

private static object _syncRoot = new Object();
public static SingletonClass Instance
    {
        get
        {
            if (_instance == null)
            {
                lock(syncRoot)
                {
                    if (_instance == null)
                        _instance = new SingletonClass();
                }
            }
            return _instance;
        }
    }

Es wird also eine neue statische, private Variable vom Typ object erzeugt und auf diese legt man dann den Sperrmechanismus an. Der erste Thread, der ankommt, wird die Variable sperren und so verhindern, dass ein anderer Thread an dieser Stelle einfach weiterläuft. Erst, wenn die Instanz-Variable fertig erzeugt ist, wird das Sperrobjekt wieder freigegeben und der andere Thread kann weiter arbeiten. Daher auch dann nochmal die zweite Abfrage, ob _instance null ist. Es könnte ja sein, dass sich dieser Zustand bereits geändert hat.

So. Das war’s eigentlich zu diesem Thema. Jetzt dürften dann aber eigentlich noch Fragen kommen, warum man dafür so umständlich ein extra Pattern dafür verwendet. Man könnte ja genauso einfach eine statische Klasse verwenden. Prinzipiell ist das richtig und in den meisten Fällen reicht auch eine statische Klasse aus. Allerdings gibt es doch ein paar kleine, aber feine Unterschiede.

Erst einmal zum wohl wichtigsten Unterschied: Eine statische Klasse ist kein Objekt sondern nur eine Ansammlung von instanzlosen Methoden, wärend ein Singleton ein vollwertiges Objekt ist. Das heißt, man kann alle Aspekte der Objektorientierung verwenden. Das wohl am häufigsten verwendete Beispiel ist da wohl die Vererbung. Man kann eine Singleton-Klasse erben lassen und auch weiter vererben. Man könnte zum Beispiel eine Singleton Basisklasse machen, mit unterschiedlichen Childklassen. Zum Beispiel verschiedene beim Connection-Objekt die Verwendung unterschiedlicher Datenbanken. Der Aufruf könnte trotzdem gleich bleiben. Man müsste dann aber den Konstruktor von private auf protected ändern, damit man das machen kann.

Der nächste wichtige Punkt ist die Wartbarkeit. Nehmen wir mal an, dass man plötzlich doch aus irgend einem Grund statt einer Einmal-Instanz eine ganz normale Klasse benötigt, die man mehrfach instanzieren kann. Bei einer statischen Klasse würde das bedeuten, dass man jeden Aufruf anpassen muss, da die Aufrufe niemals ein new voran führen. Bei Singleton muss man lediglich die Property zum holen der Instanz anpassen, damit hier jedes mal eine neue Instanz erzeugt und zurückgegeben wird.

Manchmal hört man auch noch, dass Singletons performanter und speicherschonender sein sollen. Das wag ich ehrlich gesagt zu bezweifeln. Sowohl bei Singleton als auch bei statischen Klassen wird die Klasse erst erzeugt, wenn das erste mal darauf zugegriffen wird. Vielleicht gibt es noch ein paar weitere Feinheiten die sich in diesen Bereichen auswirken können, aber die sind mir dann nicht bekannt.