Suche…


Bemerkungen

Das Singleton-Designmuster wird manchmal als " Anti-Pattern " betrachtet. Dies liegt an der Tatsache, dass es einige Probleme hat. Sie müssen selbst entscheiden, ob Sie die Verwendung für angemessen halten. Dieses Thema wurde in StackOverflow mehrmals erörtert.

Siehe: http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons

Singleton (C #)

Singletons werden verwendet, um sicherzustellen, dass nur eine Instanz eines Objekts erstellt wird. Das Singleton erlaubt nur die Erstellung einer einzigen Instanz von sich selbst, was bedeutet, dass es seine Erstellung steuert. Das Singleton ist eines der Gang-of-Four- Designmuster und ist ein kreatives Muster .

Thread-Safe-Singleton-Muster

public sealed class Singleton
{
    private static Singleton _instance;
    private static object _lock = new object();
 
    private Singleton()
    {
    }
 
    public static Singleton GetSingleton()
    {
        if (_instance == null)
        {
             CreateSingleton();
        }

        return _instance;
    }

    private static void CreateSingleton()
    {
        lock (_lock )
        {
            if (_instance == null)
            {
                 _instance = new Singleton();
            }
        }
    }
}

Jon Skeet bietet die folgende Implementierung für einen faulen, Thread-sicheren Singleton:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());
    
    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
} 

Singleton (Java)

Singletons in Java sind C # sehr ähnlich, da beide Sprachen objektorientiert sind. Nachfolgend finden Sie ein Beispiel für eine Singleton-Klasse, bei der nur eine Version des Objekts während der Laufzeit des Programms aktiv sein kann (vorausgesetzt, das Programm arbeitet mit einem Thread)

public class SingletonExample {

    private SingletonExample() { }

    private static SingletonExample _instance;

    public static SingletonExample getInstance() {

        if (_instance == null) {
            _instance = new SingletonExample();
        }
        return _instance;
    }
}

Hier ist die Thread-sichere Version dieses Programms:

public class SingletonThreadSafeExample {

    private SingletonThreadSafeExample () { }

    private static volatile SingletonThreadSafeExample _instance;

    public static SingletonThreadSafeExample getInstance() {
        if (_instance == null) {
                createInstance();
        }
        return _instance;
    }

    private static void createInstance() {
        synchronized(SingletonThreadSafeExample.class) {
            if (_instance == null) {
                _instance = new SingletonThreadSafeExample();
            }
        }
    }
}

Java verfügt auch über ein Objekt namens ThreadLocal , das eine einzelne Instanz eines Objekts auf Thread-für-Thread-Basis erstellt. Dies kann in Anwendungen nützlich sein, in denen jeder Thread eine eigene Version des Objekts benötigt

public class SingletonThreadLocalExample {

    private SingletonThreadLocalExample () { }

    private static ThreadLocal<SingletonThreadLocalExample> _instance = new ThreadLocal<SingletonThreadLocalExample>();

    public static SingletonThreadLocalExample getInstance() {
        if (_instance.get() == null) {
            _instance.set(new SingletonThreadLocalExample());
        }
        return _instance.get();
    }
}

Hier ist auch eine Singleton- Implementierung mit enum (die nur ein Element enthält):

public enum SingletonEnum {
    INSTANCE;
    // fields, methods
}

Durch die Implementierung einer Enum- Klasse wird sichergestellt, dass von jedem Element nur eine Instanz vorhanden ist.

Bill Pugh Singleton Pattern

Bill Pugh Singleton Pattern ist der am weitesten verbreitete Ansatz für die Singleton-Klasse, da keine Synchronisation erforderlich ist

public class SingletonExample {

    private SingletonExample(){}
    
    private static class SingletonHolder{
        private static final SingletonExample INSTANCE = new SingletonExample();
    }
    
    public static SingletonExample getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

Bei Verwendung der privaten inneren statischen Klasse wird der Inhaber nicht in den Speicher geladen, bis jemand die getInstance-Methode aufruft. Die Lösung von Bill Pugh ist Thread-sicher und erfordert keine Synchronisation.


Es gibt weitere Java-Singleton-Beispiele im Singletons- Thema unter dem Java-Dokumentations-Tag.

Singleton (C ++)

Wiki : In der Softwareentwicklung ist das Singleton-Muster ein Entwurfsmuster, das die Instantiierung einer Klasse auf ein Objekt beschränkt.

Dies ist erforderlich, um genau ein Objekt zu erstellen, um Aktionen innerhalb des Systems zu koordinieren.

class Singleton
{
    // Private constructor so it can not be arbitrarily created.
    Singleton()
    {}
    // Disable the copy and move
    Singleton(Singleton const&)            = delete;
    Singleton& operator=(Singleton const&) = delete;
  public:

    // Get the only instance
    static Singleton& instance()
    {
        // Use static member.
        // Lazily created on first call to instance in thread safe way (after C++ 11)
        // Guaranteed to be correctly destroyed on normal application exit.
        static Singleton _instance;

        // Return a reference to the static member.
        return _instance;
    }
};

Lazy Singleton praktisches Beispiel in Java

Anwendungsfälle im echten Leben für Singleton-Pattern;

Wenn Sie eine Client-Server-Anwendung entwickeln, benötigen Sie ConnectionManager , das den Lebenszyklus von Client-Verbindungen verwaltet.

Die grundlegenden APIs in ConnectionManager:

registerConnection : Neue Verbindung zu bestehender Verbindungsliste hinzufügen

closeConnection : Schließt die Verbindung entweder durch ein Ereignis, das vom Client oder vom Server ausgelöst wird

broadcastMessage : Manchmal müssen Sie eine Nachricht an alle abonnierten Clientverbindungen senden.

Ich biete keine vollständige Implementierung des Quellcodes an, da das Beispiel sehr langwierig wird. Auf hohem Niveau wird der Code so sein.

import java.util.*;
import java.net.*;

/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class  LazyConnectionManager {
    private Map<String,Connection> connections = new HashMap<String,Connection>();
    private LazyConnectionManager() {}
    public static LazyConnectionManager getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
    }

    /* Make sure that De-Serailzation does not create a new instance */
    private Object readResolve()  {
        return LazyHolder.INSTANCE;
    }
    public void registerConnection(Connection connection){
        /* Add new connection to list of existing connection */
        connections.put(connection.getConnectionId(),connection);
    }
    public void closeConnection(String connectionId){
        /* Close connection and remove from map */
        Connection connection = connections.get(connectionId);
        if ( connection != null) {
            connection.close();
            connections.remove(connectionId);
        }
    }
    public void broadcastMessage(String message){
        for (Map.Entry<String, Connection> entry : connections.entrySet()){
            entry.getValue().sendMessage(message);            
        }
    }    
}

Beispielserverklasse:

class Server implements Runnable{
    ServerSocket socket;
    int id;
    public Server(){
        new Thread(this).start();
    }
    public void run(){
        try{
            ServerSocket socket = new ServerSocket(4567);
            while(true){
                Socket clientSocket = socket.accept();
                ++id;
                Connection connection = new Connection(""+ id,clientSocket);
                LazyConnectionManager.getInstance().registerConnection(connection);    
                LazyConnectionManager.getInstance().broadcastMessage("Message pushed by server:");
            }
        }catch(Exception err){
            err.printStackTrace();
        }
    }
    
}

Andere praktische Anwendungsfälle für Singletons:

  1. Verwaltung globaler Ressourcen wie ThreadPool, ObjectPool, DatabaseConnectionPool usw.
  2. Zentralisierte Dienste wie Logging Anwendungsdaten mit unterschiedlichen Protokollierungsstufen wie DEBUG,INFO,WARN,ERROR usw
  3. Global RegistryService bei dem verschiedene Dienste beim Start mit einer zentralen Komponente registriert werden. Dieser globale Dienst kann als Facade für die Anwendung fungieren

C # - Beispiel: Multithread-Singleton

Die statische Initialisierung ist für die meisten Situationen geeignet. Wenn Ihre Anwendung die Instantiierung verzögern muss, einen nicht standardmäßigen Konstruktor verwenden oder vor der Instantiierung andere Aufgaben ausführen und in einer Multithread-Umgebung arbeiten muss, benötigen Sie eine andere Lösung. Es gibt jedoch Fälle, in denen Sie sich nicht auf die Common Language Runtime verlassen können, um die Thread-Sicherheit zu gewährleisten, wie im Beispiel für die statische Initialisierung. In solchen Fällen müssen Sie bestimmte Sprachfunktionen verwenden, um sicherzustellen, dass nur eine Instanz des Objekts in Gegenwart mehrerer Threads erstellt wird. Eine der gebräuchlichsten Lösungen ist die Verwendung des Double-Check Locking [Lea99] -Idoms, um zu verhindern, dass separate Threads gleichzeitig neue Instanzen des Singleton erstellen.

Bei der folgenden Implementierung kann nur ein einzelner Thread den kritischen Bereich betreten, den der Sperrblock identifiziert, wenn noch keine Instanz von Singleton erstellt wurde:

using System;

public sealed class Singleton {    
   private static volatile Singleton instance;    
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance    {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }    
  } 
}

Dieser Ansatz stellt sicher, dass nur eine Instanz erstellt wird und nur, wenn die Instanz benötigt wird. Außerdem wird die Variable als flüchtig deklariert, um sicherzustellen, dass die Zuweisung zu der Instanzvariablen abgeschlossen ist, bevor auf die Instanzvariable zugegriffen werden kann. Schließlich verwendet dieser Ansatz eine syncRoot-Instanz zum Sperren anstelle des Typs selbst, um Deadlocks zu vermeiden.

Durch diesen doppelten Check-Locking-Ansatz werden die Thread-Parallelitätsprobleme gelöst, während bei jedem Aufruf der Instance-Eigenschaftsmethode eine exklusive Sperre vermieden wird. Außerdem können Sie die Instantiierung verzögern, bis auf das Objekt zum ersten Mal zugegriffen wird. In der Praxis erfordert eine Anwendung diese Art der Implementierung selten. In den meisten Fällen ist der Ansatz der statischen Initialisierung ausreichend.

Referenz: MSDN

Danksagungen

[Gamma95] Gamma, Helm, Johnson und Vlissides. Design Patterns: Elemente wiederverwendbarer objektorientierter Software. Addison-Wesley, 1995.

Lea, Doug. Parallele Programmierung in Java, Zweite Ausgabe. Addison-Wesley, 1999.

[Sells03] Verkauft, Chris. "Versiegelt saugt." sellsbrothers.com Nachrichten. Verfügbar unter: http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 .

Singleton (PHP)

Beispiel von phptherightway.com

<?php
class Singleton
{
    /**
     * @var Singleton The reference to *Singleton* instance of this class
     */
    private static $instance;
    
    /**
     * Returns the *Singleton* instance of this class.
     *
     * @return Singleton The *Singleton* instance.
     */
    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }
        
        return static::$instance;
    }

    /**
     * Protected constructor to prevent creating a new instance of the
     * *Singleton* via the `new` operator from outside of this class.
     */
    protected function __construct()
    {
    }

    /**
     * Private clone method to prevent cloning of the instance of the
     * *Singleton* instance.
     *
     * @return void
     */
    private function __clone()
    {
    }

    /**
     * Private unserialize method to prevent unserializing of the *Singleton*
     * instance.
     *
     * @return void
     */
    private function __wakeup()
    {
    }
}

class SingletonChild extends Singleton
{
}

$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance());             // bool(true)

$anotherObj = SingletonChild::getInstance();
var_dump($anotherObj === Singleton::getInstance());      // bool(false)

var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)

Singleton Design Pattern (allgemein)

Hinweis: Das Singleton ist ein Designmuster.
Es wurde aber auch ein Anti-Muster betrachtet.

Die Verwendung eines Singleton sollte vor der Verwendung sorgfältig geprüft werden. Es gibt normalerweise bessere Alternativen.

Das Hauptproblem bei einem Singleton ist das gleiche wie bei globalen Variablen. Sie führen einen externen, global veränderbaren Zustand ein. Dies bedeutet, dass Funktionen, die ein Singleton verwenden, nicht nur von den Eingabeparametern, sondern auch vom Status des Singleton abhängig sind. Dies bedeutet, dass das Testen stark beeinträchtigt werden kann (schwierig).

Die Probleme mit Singletons können gemindert werden, indem sie in Verbindung mit Erstellungsmustern verwendet werden. so dass die anfängliche Erstellung des Singleton gesteuert werden kann.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow