Singleton (Entwurfsmuster)

Entwurfsmuster in objektorientierter Softwareentwicklung
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 10. August 2006 um 13:32 Uhr durch Herr Schroeder (Diskussion | Beiträge) (C#-Implementierung in das richtige Kapitel (Eager Creation) verschoben). Sie kann sich erheblich von der aktuellen Version unterscheiden.

Das Einzelstück (engl. Singleton) ist ein in der Softwareentwicklung eingesetztes Entwurfsmuster und gehört zur Kategorie der Erzeugungsmuster (engl. Creational Patterns). Es stellt sicher, dass zu einer Klasse nur genau ein Objekt erzeugt werden kann und ermöglicht einen globalen Zugriff auf dieses Objekt. Das Muster gehört mit dem Iterator-Entwurfsmuster zu den bekanntesten der von der so genannten Viererbande publizierten Muster.

Verwendung

Das Einzelstück findet Verwendung, wenn

  • nur ein Objekt zu einer Klasse existieren darf und ein einfacher Zugriff auf dieses Objekt benötigt wird oder
  • wenn das einzige Objekt durch Unterklassenbildung spezialisiert werden soll.

Anwendungsbeispiele sind:

  • Ein zentrales Protokoll-Objekt, das Ausgaben in eine Datei schreibt.
  • Druckaufträge, die zu einem Drucker gesendet werden, sollten nur in einen einzigen Puffer geschrieben werden.

UML-Diagramm

Singleton
instance : Singleton
– Singleton()
+ getInstance() : Singleton

Akteure

  • Einzelstück
    • erzeugt und verwaltet einziges Objekt zu einer Klasse
    • bietet globalen Zugriff auf dieses Objekt über eine Instanzoperation
    • die Instanzoperation ist eine Klassenmethode, d. h. statisch gebunden
    • (das Attribut „Instanz“ ist ein Klassenattribut, d. h. ein statisches Attribut)

Vorteile

  • Das Muster bietet eine Verbesserung gegenüber globalen Variablen.
  • Das Einzelstück kann durch Unterklassenbildung spezialisiert werden.
  • Sollten später mehrere Objekte benötigt werden, ist eine Änderung leicht möglich.

Nachteile

  • In einigen objektorientierten Programmiersprachen gibt es keine Möglichkeit, Klassenmethoden zu beschreiben.
  • Es besteht die Gefahr, durch exzessive Verwendung von Singletons quasi ein objektorientiertes Äquivalent zu globalen Variablen zu implementieren.
  • In DLLs (dynamic link libraries) lassen sich (zumindest in C++) Singletons nur eingeschränkt verwenden. Da DLLs nicht wie zum Beispiel Libraries zum Programm gelinkt werden, sondern von Haus aus gelinkt sind, wird ein Singleton, das in einer DLL und dem Hauptprogramm verwendet wird, in beiden Modulen ein eigenes Objekt sein. Das kann man (umständlich) vermeiden, indem das Hauptprogramm die eigene Instanz des Singleton an die DLL übergibt.

Beispiel

Lazy Creation

Von Lazy Creation spricht man, wenn das einzige Objekt der Klasse erst erzeugt wird, wenn es benötigt wird.

Nachteil: Der Programmierer ist selbst für Thread-Sicherheit verantwortlich (z. B. Java: mit synchronized).

Implementierung in Java

Die Erstellung des einmalig existierenden Objekts wird folgendermaßen erreicht:

  • Der Konstruktor der Singleton-Klasse ist privat. So ist es von außen nicht möglich, ein weiteres Objekt dieser Klasse zu erzeugen.
  • Als Ersatz wird eine neue Zugriffsmethode angelegt, die eine Referenz auf das einzige Objekt zurückgeben kann.
  • Die Variable, in der das Objekt gespeichert wird, erhält den Modifikator „statisch“ („static“). Sie ist außerdem synchronisiert um die Sicherheit bei nebenläufiger Ausführung zu gewährleisten. Eine alternative Implementierung, die ohne Synchronisierung auskommt, ist unten unter Eager Creation gezeigt.
 public final class Singleton {

     /** 
      * Privates Klassenattribut, 
      * wird beim erstmaligen Gebrauch (nicht beim Laden) der Klasse erzeugt
      */
     private static Singleton instance;

     /** Konstruktor ist privat, darf nicht von außen instanziiert werden. */
     private Singleton() {}

     /** 
      * Statische Methode "getInstance()" liefert die einzige Instanz der Klasse zurück.
      * Ist synchronisiert und somit thread-sicher.
      */
     public synchronized static Singleton getInstance() {
         if (instance == null) {
             instance = new Singleton();
         }
         return instance;
     }

 }

Implementierung in C++

Vorsicht: Die beiden folgenden Implementierungen sind nicht korrekt, da mehr als nur eine Instanz erstellt werden kann, sofern mehrere Threads gleichzeitig getInstance() aufrufen. Sie dienen nur als Beispiel und sollten in dieser Form ohne Locking nicht in großen Projekten verwendet werden SINGLETON PATTERN - THREAD SAFETY.

Erste Methode: hat den Vorteil, dass bei Programmende das Objekt automatisch zerstört wird (und der Destruktor aufgerufen wird). Darüber, wann das passiert, hat man aber keine Kontrolle.

 class Singleton
 {
   private:
     //Konstruktor private, damit man sich keine Instanzen holen kann.
     Singleton();
     //Den Kopierkonstruktor schützen um zu vermeiden, dass das Objekt unbeabsichtigt kopiert wird.
     Singleton(const Singleton& cc){}
  
   public:
     ~Singleton();
     static Singleton* getInstance();
 };
  
 Singleton* Singleton::getInstance()
 {
   static Singleton instance; 
   return &instance; 
 }

Zweite Methode: Vorteil dieser ist, dass man bei Erzeugung des Objektes ein spezialisiertes Objekt erzeugen kann, man hat also Polymorphie. Außerdem hat man durch Hinzufügen einer statischen Destroy()-Funktion volle Kontrolle darüber, wann das Singleton wieder zerstört wird.

 class Singleton
 {
   private:
     //Ein Pointer zum Speichern der Instanz
     static Singleton* instance;
     //Konstruktor private, damit man sich keine Instanzen holen kann.
     Singleton();
     //Den Kopierkonstruktor schützen um zu vermeiden, dass das Objekt unbeabsichtigt kopiert wird.
     Singleton(const Singleton& cc){}
     ~Singleton();
   public:
     static Singleton* getInstance();
     static void Destroy();  
};
 
 Singleton* Singleton::instance = 0;
 
 Singleton* Singleton::getInstance()
 {
   if( !instance )
     instance = new Singleton();
   return instance;
 }
 
 void Singleton::Destroy()
 {
  // static 
  delete instance; 
  instance= 0; 
 }

Implementierung in PHP (ab Version 5)

<?php
class Singleton {
  /**
   * die Instanz wird hier abgelegt
   */
  private static $instance = NULL;
  
  /**
   * Konstruktor private, damit die Klasse nur aus sich selbst heraus instanziert werden kann.
   */
  private function __construct() {}

  /**
   * mit dieser statischen Methode bekommt man das Singleton
   */
  public static function getInstance()
  {
      if (self::$instance === NULL)
      {
          self::$instance = new Singleton;
      }
      return self::$instance;
  }

  /**
   * Klonen per 'clone' von außen verbieten
   */
  private function __clone() {}
}

$single = Singleton::getInstance();
?>

Eager Creation

Zwar ist auch das oben gezeigte Beispiel sicher bezüglich Nebenläufigkeit, weil die zentrale Methode getInstance mit dem Java-Schlüsselwort synchronized markiert ist. Eine einfachere Alternative dazu stellt jedoch die Möglichkeit dar, das Einzelstück bereits während der Initialisierung der Klasse zu erzeugen, die Zugriffsmethode muss es dann nur noch zurück geben. Daher muss sie nicht synchronisiert werden, was den Zugriff etwas beschleunigt. Dieses Verfahren ist auch als eager creation (deutsch „begierige Erzeugung“) bekannt.

Implementierung in Java

 public final class Singleton {

     /** Privates Klassenattribut, einzige Instanz der Klasse wird erzeugt. */
     private static final Singleton INSTANCE = new Singleton();

     /** Konstruktor ist privat, darf nicht von außen instanziiert werden. */
     private Singleton() {}

     /** Statische Methode "getInstance()" liefert die einzige Instanz der Klasse zurück. */ 
     public static Singleton getInstance() {
         return INSTANCE;
     }

}

Implementierung in C#

Eine Thread-sichere Methode entnommen aus dem MSDN-Mag[1].

 using System ;
 
 sealed class Singleton
 {
   private Singleton(){}
   public static readonly Singleton Instance = new Singleton() ;
 }
 
 // Zugriff über
 Singleton s = Singleton.Instance ;

Das Borg Pattern

Unter Python gibt es auch mehrere Ansätze für das Singleton Entwurfsmuster, allerdings wird hier allgemein eher das Borg Pattern angewendet:

class Borg(object):
    _shared = {}
    def __new__(cls,*args,**kwargs):
        inst = object.__new__(cls)
        inst.__dict__ = cls._shared

Im Gegensatz zum Singleton können mehrere Instanzen erstellt werden, allerdings teilen sich alle Instanzen der Borg Klasse ihre Attribute.

Der Name Borg stammt aus einem Posting von Alex Martelli im ASPN.[2]

Verwandte Entwurfsmuster

Die Eigenschaften des Einzelstückes treffen für viele Klassen der anderen Muster zu, so dass diese dann als Einzelstücke ausgeführt werden.

Zum Beispiel sind abstrakte Fabriken, Erbauer oder Prototypen oft auch Einzelstücke.

Quellen

  1. http://msdn.microsoft.com/msdnmag/issues/03/02/CQA/
  2. Alex Martelli: Singleton? We don't need no stinkin' singleton: the Borg design pattern. Posting im „ActiveState Programmer Network“ vom 27. August 2001 [22. Januar 2006]