Ein
Singleton ist eine Klasse von der es nur eine einzige Instanz gibt.
Wie man genau sicherstellt dass es nur eine Instanz gibt soll nicht Thema dieses Tutorials sein.
Es gibt allerdings verschiedene Arten von Singletons:
A)
write-only Singleton
Ein typischer Vertreter dieser Art ist z.B. eine Klasse zur Ausgabe von Loginformation:
Delphi-Quellcode:
type
TLogger = class(TObject)
private
FStream : TFileStream;
procedure Open(const filename:String);
public
constructor Create(const filename:String);
destructor Destroy;override;
procedure WriteLog(const msg:string);
procedure WriteLogFmt(const msg: string; const args: array of const);
class function GetLogger:TLogger;
end;
Dieser Singleton ist für den Aufrufer quasi ohne
Seiteneffekte, da man die Methoden
WriteLog
und
WriteLogFmt
jederzeit (und in beliebiger Reihenfolge!) aufrufen kann ohne dass es einen Einfluss auf nachfolgende Aufrufe hat.
Der innere Zustand kann sich zwar ändern aber es gibt keinen Weg auf dem diese Änderung eine Auswirkung auf den Aufrufer haben könnte.
Bei mehreren Threads müssen die Methoden ggf. mit einer Critical Section geschützt werden, damit die Logausgaben sich nicht vermischen können.
B)
immutable (read-only) Singleton
Ein immutable Singleton wird nur einmal zu Beginn mit Daten initialisiert und kann seinen inneren Zustand während seiner gesamten Lebensdauer nicht mehr verändern.
Er bietet seine Daten in der Regel über read-only Properties oder Funktionen an.
Ein Beispiel dafür wäre eine Klasse die Lizenzinformation bereithält und von der Anwendung immer wieder ausgelesen wird.
Diese Art von Singletons hat keine Seiteneffekte weil sich der innere Zustand nicht mehr ändern kann.
Daher ist dieser Singleton auch threadsicher und braucht nicht durch Critical Section, Mutexe oder Ähnliches geschützt werden.
C)
read/write Singleton
Diese Art von Singleton ist sehr problematisch!
Der Aufrufer kann über Methoden und/oder Properties sowohl den inneren Zustand ändern als auch den geänderten Zustand direkt oder indirekt auslesen.
Im Grund stellt dieser Singleton nichts anderes dar als eine Reihe von globalen Variablen die in einem Objekt verpackt wurden.
Die Aufrufer des Singletons sind nicht voneinander isoliert sondern sehr stark gekoppelt.
Fazit:
Bei Singletons sollte man unbedingt darauf achten, dass man keinesfalls einen read/write Singleton (das Äquivalent zu globalen Variablen) erstellt.
Immutable Singletons können dagegen als sicher angesehen werden.
Write-only Singletons sind meistens sicher wobei man aber darauf achten muss, dass Änderungen des inneren Zustands nicht nach Aussen dringen dürfen.
Write-Only und Immutable Singleton können sogar gemeinsam in einer Mischform auftreten.
Dazu braucht man das Beispiel vom Anfang nur etwas erweitern:
Delphi-Quellcode:
type
TLogger = class(TObject)
private
FStream : TFileStream;
FFilename : String; // <==
procedure Open(const filename:String);
public
constructor Create(const filename:String);
destructor Destroy;override;
....
property Filename:String read FFilename; // <==
Man sieht dass jetzt zusätzlich das Property Filename hinzugekommen ist das der Aufrufer auslesen kann.
Ausserdem kann er weiterhin über die Methoden WriteLog und WriteLogFmt schreibend zugreifen.
Da sich aber das Property Filename nicht mehr ändern kann ist dies unproblematisch.
Allerdings können schon kleine Änderungen am Code sich so auswirken dass wiederum ein read/write Singleton entsteht.