Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

33.1 Singleton

33.1 Singleton

Ein Singleton ist eine Klasse, von welcher man programmweit nur ein Instanz erzeugen kann. In der Regel steht es dann global zur Verfügung und kann somit von überall verwendet werden. Doch wofür braucht man so etwas? Man entscheidet sich immer für eine Singletonklasse, wenn deren Erzeugung teuer ist (zeitaufwändig und oder speicherintensiv). Normalerweise handelt es sich dann um Klassen, welche zentrale Aufgaben übernehmen und somit theoretisch auch nur einmal benötigt werden.

Doch wie erreicht man es, dass man nur eine Instanz einer Klasse erzeugen kann? Die Grundidee ist, dass man das Objekt nicht an einer beliebigen Stelle erzeugt (es sogar verbietet), sondern in einer statischen Klassenmethode, welche gleichzeitig kontrolliert, dass es eben nur eine Instanz gibt. Die Instanz selbst, wird auch in einer statischen Variable gespeichert.

Vereinfachte Struktur eines Singleton

Wie verbietet man nun, dass man eine Instanz erzeugen bzw. freigeben kann? Hierfür muss man nur die Konstruktoren, gewisse Operatoren und den Destruktor als privat deklarieren. Die statische Klassenmethode darf auf die Konstruktoren zugreifen, aber nicht die Außenwelt.

Um Ihnen dies zu demonstrieren, habe ich mir ein kleines Beispiel einfallen lassen, welches schematisch einen Datenbankclient repräsentiert. Da man in der Regel eine zentrale Verbindung zur Datenbank hat, kann das Verbindungsobjekt von einer Singletonklasse sein und alle internen Module können gemeinsam diese Verbindung nutzen.

Möglicher Aufbau eines Datenbankclients

Aus Gründen der Übersichtlichkeit, konzentriere ich mich jetzt nur auf die Definition und Implementierung der Singletonklasse. Schauen Sie sich zunächst die Header-Datei an.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
					
// Klasse zur Kapselung einer Datenbankverbindsung
class CSingletonDBConnection {
	private:
		static CSingletonDBConnection* s_pConnection;

		// Standardkonstruktor – Erzeugung von außen verhindern
		CSingletonDBConnection() {}
		// Kopierkonstruktor – Erzeugung von außen verhindern
		CSingletonDBConnection(const CSingletonDBConnection&) {}
		// Zuweisungsoperator – Erzeugung von außen verhindern
		CSingletonDBConnection& operator=(const CSingletonDBConnection&) {}
		// Destruktor – Freigeben von außen verhindern
		~CSingletonDBConnection() {}

	public:
		// Ggf. Objekt erzeugen und Referenz zurückgeben
		static CSingletonDBConnection* GetInstance();
		// Kontrolliertes Löschen
		static void Destroy();
};
					

Wie Sie sehen, habe ich eine statische Klassenvariable, welche später auf die eine erzeugte Instanz verweisen wird. Zudem habe ich die Konstruktoren und den Zuweisungsoperator privat deklariert. Da ich Ihnen, wie gesagt, nur das Prinzip zeigen möchte, haben diese Methoden keine weitere Logik.

Im öffentlichen Bereich gibt es jetzt zwei statische Methoden. Normalerweise reicht die Methode "GetInstance", aber die Methode "Destroy" ist ganz praktisch, da ich so entscheiden kann, wann das Objekt freigegeben wird. Würde ich mir nicht einen solchen Mechanismus bauen, würde das Objekt irgendwann bei Programmende freigegeben werden. Wann genau, kann man aber nicht sagen. So habe ich volle Kontrolle über meine Datenbankverbindung. Auch hier müsste ich eigentlich noch solche Informationen wie Verbindungsdaten mit übergeben, aber aus Gründen der Einfachheit, habe ich mir das an dieser Stelle auch gespart.

Schauen Sie sich als nächstes die Implementierung der zwei statischen Klassenmethoden in der CPP-Datei an.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
					
#include <stdlib.h>
#include "SingletonDBConnection.h"

CSingletonDBConnection* CSingletonDBConnection::s_pConnection = NULL;



// Ggf. Objekt erzeugen und Referenz zurückgeben //////////////////////////////
CSingletonDBConnection* CSingletonDBConnection::GetInstance() {
	// Wenn die Verbindung noch nicht erzeugt wurde
	if (s_pConnection == NULL) s_pConnection = new CSingletonDBConnection();

	return s_pConnection;
} // GetInstance //////////////////////////////////////////////////////////////



// Kontrolliertes Löschen /////////////////////////////////////////////////////
void CSingletonDBConnection::Destroy() {
	// Nur wenn schon eine Instanz erzeugt wurde
	if (s_pConnection != NULL) delete s_pConnection;

	s_pConnection = NULL;
} // Destroy //////////////////////////////////////////////////////////////////
					

Was hier passiert, ist eigentlich keine große Magie. Zu Beginn, in Zeile 4, initialisiere ich das statische Klassenattribut. Diese Schreibweise sollte Ihnen ja schon bekannt sein. In den zwei Methoden prüfe ich jetzt nur, ob die Instanz schon erzeugt bzw. freigegeben wurde und wenn dem nicht so ist, sorge ich dafür, dass dies geschieht. Ansonsten wird nur ein Zeiger auf die Instanz zurückgegeben bzw. das statische Klassenattribut zurückgesetzt.

Der Vollständigkeit halber, folgt nun die Verwendung dieser Klasse von außen.

 1
 2
 3
 4
 5
 6
					
CSingletonDBConnection* pConnection	= CSingletonDBConnection::GetInstance();

// ...

CSingletonDBConnection::Destroy();
pConnection				= NULL;
					

Wann immer Sie also etwas von "GetInstance" lesen, können Sie sich fast sicher sein, dass das Singleton Pattern zum Einsatz kommt und welche Folgen sich daraus ergeben.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012