Singleton-Muster - Singleton pattern
In der Softwareentwicklung ist das Singleton-Muster ein Software-Entwurfsmuster, das die Instanziierung einer Klasse auf eine "einzelne" Instanz beschränkt. Dies ist nützlich, wenn genau ein Objekt benötigt wird, um Aktionen im gesamten System zu koordinieren.
Der Begriff stammt aus dem mathematischen Konzept eines Singletons .
Überblick
Das Singleton Design Pattern ist eines der dreiundzwanzig bekannten "Gang of Four" Design Patterns , die beschreiben, wie wiederkehrende Designprobleme gelöst werden können, um flexible und wiederverwendbare objektorientierte Software zu entwerfen mit dem Ziel, die Implementierung, Änderung, Testen und Wiederverwenden von Objekten.
Das Singleton-Entwurfsmuster löst Probleme, indem es Folgendes ermöglicht:
- Stellen Sie sicher, dass eine Klasse nur eine Instanz hat
- Einfach auf die einzige Instanz einer Klasse zugreifen
- Kontrollieren Sie seine Instanziierung
- Beschränken Sie die Anzahl der Instanzen
- Auf eine globale Variable zugreifen
Das Singleton-Design-Pattern beschreibt, wie solche Probleme gelöst werden können:
- Blenden Sie die Konstruktoren der Klasse aus .
- Definieren Sie eine öffentliche statische Operation (
getInstance()
), die die einzige Instanz der Klasse zurückgibt.
Im Wesentlichen zwingt das Singleton-Muster es dazu, dafür zu sorgen, dass es nur einmal instanziiert wird. Ein versteckter Konstruktor – deklariert private
oder – stellt protected
sicher, dass die Klasse niemals von außerhalb der Klasse instanziiert werden kann. Auf die öffentliche statische Operation kann über den Klassennamen und den Operationsnamen zugegriffen werden, zB Singleton.getInstance()
.
Häufige Verwendungen
- Die Muster abstrakte Fabrik , Fabrikmethode , Builder und Prototyp können Singletons verwenden.
- Fassadenobjekte sind oft Singletons, da nur ein Fassadenobjekt benötigt wird.
- Zustandsobjekte sind oft Singletons.
- Singletons werden häufig globalen Variablen vorgezogen, weil:
- Sie beschmutzen den globalen Namensraum (oder in Sprachen mit verschachtelten Namensräumen den darin enthaltenen Namensraum) nicht mit unnötigen Variablen.
- Sie erlauben eine verzögerte Zuweisung und Initialisierung, während globale Variablen in vielen Sprachen immer Ressourcen verbrauchen.
Die Protokollierung ist ein klassisches Beispiel für einen Singleton.
Kritik
Kritiker halten das Singleton insofern für ein Anti-Muster , als es häufig in Szenarien verwendet wird, in denen es nicht von Vorteil ist, da es oft unnötige Einschränkungen in Situationen einführt, in denen eine Singleton-Klasse nicht von Vorteil wäre, wodurch ein globaler Zustand in eine Anwendung eingeführt wird.
Da auf ein Singleton von überall aus zugegriffen werden kann, ohne Parameter verwenden zu müssen, wären außerdem alle Abhängigkeiten für Entwickler nicht sofort sichtbar. Folglich müssten Entwickler "das Innenleben des Codes kennen, um ihn richtig zu verwenden".
Singletons verstoßen auch gegen das Single-Responsibility-Prinzip , da sie nicht nur für die normale Aufgabe des Singletons verantwortlich sind, sondern auch dafür sorgen müssen, dass nur einer instanziiert wird; Beachten Sie, dass dies auf einer "klassischen" Singleton-Definition beruht, bei der sie für die Durchsetzung ihrer eigenen Eindeutigkeit beispielsweise durch eine statische getInstance()
Methode verantwortlich ist.
Ein weiterer Nachteil besteht darin, dass Singletons schwer zu testen sind, da sie für die Dauer des Programms einen globalen Status tragen. Insbesondere, weil Unit-Tests lose gekoppelte Klassen erfordern, um zu isolieren, was getestet wird. Wenn eine bestimmte Klasse mit einem Singleton interagiert, werden diese Klasse und der Singleton außerdem eng gekoppelt , sodass es unmöglich ist, die Klasse alleine zu testen, ohne auch den Singleton zu testen.
Implementierungen
Implementierungen des Singleton-Musters müssen:
- Stellen Sie sicher, dass immer nur eine Instanz der Singleton-Klasse existiert; und
- Stellen Sie globalen Zugriff auf diese Instanz bereit.
In der Regel geschieht dies durch:
- Alle Konstruktoren der Klasse als privat deklarieren ; und
- Bereitstellen einer statischen Methode , die einen Verweis auf die Instanz zurückgibt .
Die Instanz wird normalerweise als private statische Variable gespeichert ; die Instanz wird erstellt, wenn die Variable initialisiert wird, bevor die statische Methode zum ersten Mal aufgerufen wird.
Java
Singleton-Implementierung in Java :
public class Coin {
private static final int ADD_MORE_COIN = 10;
private int coin;
private static Coin instance = new Coin(); // eagerly loads the singleton
private Coin(){
// private to prevent anyone else from instantiating
}
public static Coin getInstance() {
return instance;
}
public int getCoin() {
return coin;
}
public void addMoreCoin() {
coin += ADD_MORE_COIN;
}
public void deductCoin() {
coin--;
}
}
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
Faule Initialisierung
Eine Singleton-Implementierung kann Lazy Initialization verwenden , wobei die Instanz erstellt wird, wenn die statische Methode zum ersten Mal aufgerufen wird. Wenn die statische Methode könnte aus mehreren aufgerufen werden Threads gleichzeitig, können Maßnahmen ergriffen werden müssen , um zu verhindern Rennbedingungen , die bei der Schaffung von mehreren Instanzen führen könnten. Das Folgende ist eine Thread-sichere Implementierung, die eine verzögerte Initialisierung mit doppelt geprüftem Sperren verwendet und in Java geschrieben ist. Um den Synchronisations-Overhead zu vermeiden und gleichzeitig eine verzögerte Initialisierung mit Thread-Sicherheit beizubehalten, besteht der bevorzugte Ansatz in Java darin, das Initialization-on-Demand-Halter-Idiom zu verwenden .
public final class Singleton {
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Python
class Singleton:
__instance = None
def __new__(cls, *args):
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args)
return cls.__instance
C++
Ab C++11 ist die Initialisierung statischer lokaler Variablen threadsicher und erfolgt nach dem ersten Aufruf. Dies ist eine sicherere Alternative als ein Namespace oder eine statische Variable mit Klassenbereich.
class Singleton {
public:
static Singleton& GetInstance() {
// Allocate with `new` in case Singleton is not trivially destructible.
static Singleton* singleton = new Singleton();
return *singleton;
}
private:
Singleton() = default;
// Delete copy/move so extra instances can't be created/moved.
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
};
C#
Singleton-Implementierung in C# :
public sealed class Singleton
{
public static Singleton Instance { get; } = new Singleton();
private Singleton() { }
}
In C# können Sie auch statische Klassen verwenden, um Singletons zu erstellen, wobei die Klasse selbst der Singleton ist.
public static class Singleton
{
public static MyOtherClass Instance { get; } = new MyOtherClass();
}
Einheit
Singletons können dank der Instanziierung von Klassen ein nützliches Werkzeug bei der Entwicklung mit Unity sein . Diese Methode wird dem Verbergen von Konstruktoren vorgezogen , da es möglich ist, ein Objekt mit einem versteckten Konstruktor in Unity zu instanziieren. Um zu verhindern, dass eine Instanz überschrieben wird, muss überprüft werden, ob die Instanz null
. Wenn es nicht null ist, sollte das GameObject
Skript , das das anstößige Skript enthält, zerstört werden.
Wenn andere Komponenten vom Singleton abhängig sind, sollte die Ausführungsreihenfolge des Skripts geändert werden, um sicherzustellen, dass die Komponente, die das Singleton definiert, zuerst ausgeführt wird.
class Singleton : MonoBehaviour
{
public static Singleton Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this) {
Destroy(this.gameObject);
} else {
Instance = this;
}
}
}
Beachten Sie, dass es auch möglich ist, ein Singleton zu implementieren, indem Sie nur das anstößige Skript entfernen, nicht das GameObject
selbst, indem Sie stattdessen aufrufen Destroy(this)
.
Pfeil
Singleton-Implementierung in Dart :
class Singleton {
Singleton._();
static Singleton get instance => Singleton._();
}
PHP
Singleton-Implementierung in PHP :
class Singleton
{
private static $instance = null;
private function __construct() {}
public static function getInstance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
Kotlin
Das Kotlin- Objektschlüsselwort deklariert eine Singleton-Klasse
object Coin {
private var coin: Int = 0
fun getCoin():Int {
return coin
}
fun addCoin() {
coin += 10
}
fun deductCoin() {
coin--
}
}
Pascal
Eine threadsichere Implementierung eines Singletons in Pascal :
unit SingletonPattern;
interface
type
TTest = class sealed
strict private
FCreationTime: TDateTime;
public
constructor Create;
property CreationTime: TDateTime read FCreationTime;
end;
function GetInstance: TTest;
implementation
uses
SysUtils
, SyncObjs
;
var
FCriticalSection: TCriticalSection;
FInstance: TTest;
function GetInstance: TTest;
begin
FCriticalSection.Acquire;
try
if not Assigned(FInstance) then
FInstance := TTest.Create;
Result := FInstance;
finally
FCriticalSection.Release;
end;
end;
constructor TTest.Create;
begin
inherited Create;
FCreationTime := Now;
end;
initialization
FCriticalSection := TCriticalSection.Create;
finalization
FreeAndNil(FCriticalSection);
end.
Verwendungszweck:
procedure TForm3.btnCreateInstanceClick(Sender: TObject);
var
i: integer;
begin
for i := 0 to 5 do
ShowMessage(DateTimeToStr(GetInstance.CreationTime));
end;
Siehe auch
Verweise
Externe Links
- Vollständiger Artikel " Java Singleton Pattern erklärt "
- Vier verschiedene Möglichkeiten zur Implementierung von Singleton in Java " Möglichkeiten zur Implementierung von Singleton in Java "
- Buchauszug: Implementieren des Singleton-Musters in C# von Jon Skeet
- Singleton im Microsoft Patterns & Practices Developer Center
- IBM-Artikel " Doppelt geprüftes Sperren und das Singleton-Muster " von Peter Haggar
- Geary, David (25. April 2003). "Wie man das täuschend einfache Singleton-Muster navigiert" . Java-Entwurfsmuster. JavaWelt . Abgerufen 2020-07-21 .
- Google Singleton Detector (analysiert Java-Bytecode , um Singletons zu erkennen)