Zoeken…


Opmerkingen

Het ontwerppatroon van Singleton wordt soms beschouwd als " Antipatroon ". Dit komt door het feit dat het enkele problemen heeft. U moet zelf beslissen of u denkt dat het gepast is om het te gebruiken. Dit onderwerp is verschillende keren besproken op StackOverflow.

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

Singleton (C #)

Singletons worden gebruikt om ervoor te zorgen dat slechts één instantie van een object wordt gemaakt. De singleton staat slechts één exemplaar van zichzelf toe, wat betekent dat het de creatie ervan bestuurt. De singleton is een van de Gang of Four- ontwerppatronen en is een creatief patroon .

Draadveilig Singleton-patroon

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 biedt de volgende implementatie voor een luie, thread-safe 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 lijken erg op C #, omdat beide talen objectgeoriënteerd zijn. Hieronder is een voorbeeld van een singleton-klasse, waar slechts één versie van het object kan leven tijdens de levensduur van het programma (ervan uitgaande dat het programma op één thread werkt)

public class SingletonExample {

    private SingletonExample() { }

    private static SingletonExample _instance;

    public static SingletonExample getInstance() {

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

Hier is de thread veilige versie van dat programma:

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 heeft ook een object met de naam ThreadLocal , dat een enkele instantie van een object op een thread per thread-basis maakt. Dit kan handig zijn in toepassingen waarbij elke thread een eigen versie van het object nodig heeft

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 is ook een Singleton- implementatie met enum (die slechts één element bevat):

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

Elke Enum- klasse-implementatie zorgt ervoor dat er slechts één instantie is waarvan elk element zal bestaan.

Bill Pugh Singleton-patroon

Bill Pugh Singleton Pattern is de meest gebruikte benadering voor de Singleton-klasse omdat het geen synchronisatie vereist

public class SingletonExample {

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

bij het gebruik van privé statische binnenklasse wordt de houder niet in het geheugen geladen totdat iemand de methode getInstance aanroept. De Bill Pugh-oplossing is thread-safe en vereist geen synchronisatie.


Er zijn meer voorbeelden van Java singleton in het onderwerp Singletons onder de tag Java-documentatie.

Singleton (C ++)

Volgens Wiki : In software engineering is het singleton-patroon een ontwerppatroon dat de instantiatie van een klasse tot één object beperkt.

Dit is vereist om precies één object te maken om acties in het systeem te coördineren.

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 praktisch voorbeeld in Java

Real life use cases voor Singleton patroon;

Als u een client-server-applicatie ontwikkelt, hebt u een enkele instance van ConnectionManager , die de levenscyclus van clientverbindingen beheert.

De basis-API's in ConnectionManager:

registerConnection : nieuwe verbinding toevoegen aan bestaande lijst met verbindingen

closeConnection : sluit de verbinding via een gebeurtenis die wordt geactiveerd door Client of Server

broadcastMessage : soms moet u een bericht sturen naar alle geabonneerde clientverbindingen.

Ik bied geen volledige implementatie van broncode, omdat het voorbeeld erg lang zal worden. Op hoog niveau ziet de code er zo uit.

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);            
        }
    }    
}

Voorbeeldserverklasse:

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 gebruikstoepassingen voor singletons:

  1. Beheer van wereldwijde bronnen zoals ThreadPool, ObjectPool, DatabaseConnectionPool etc.
  2. Gecentraliseerde services zoals Logging applicatiegegevens met verschillende Logging zoals DEBUG,INFO,WARN,ERROR enz
  3. Global RegistryService waarbij verschillende services worden geregistreerd met een centraal onderdeel bij het opstarten. Die wereldwijde service kan fungeren als een Facade voor de toepassing

C # Voorbeeld: multithreaded singleton

Statische initialisatie is geschikt voor de meeste situaties. Wanneer uw toepassing de instantiëring moet vertragen, een niet-standaardconstructor moet gebruiken of andere taken moet uitvoeren vóór de instantiëring en in een multithreaded omgeving moet werken, heeft u een andere oplossing nodig. Er zijn echter gevallen waarin u niet kunt vertrouwen op de gangbare taal runtime om de veiligheid van threads te waarborgen, zoals in het voorbeeld van statische initialisatie. In dergelijke gevallen moet u specifieke taalmogelijkheden gebruiken om ervoor te zorgen dat slechts één exemplaar van het object wordt gemaakt in aanwezigheid van meerdere threads. Een van de meest voorkomende oplossingen is het gebruik van het ID-symbool Double-Check Locking [Lea99] om te voorkomen dat afzonderlijke threads tegelijkertijd nieuwe exemplaren van de singleton maken.

De volgende implementatie staat slechts één thread toe om het kritieke gebied binnen te gaan, dat door het vergrendelingsblok wordt geïdentificeerd, wanneer er nog geen instantie van Singleton is gemaakt:

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;
      }    
  } 
}

Deze aanpak zorgt ervoor dat slechts één exemplaar wordt gemaakt en alleen wanneer het exemplaar nodig is. Ook wordt de variabele vluchtig verklaard om ervoor te zorgen dat de toewijzing aan de instantievariabele wordt voltooid voordat de instantievariabele kan worden geopend. Ten slotte gebruikt deze benadering een syncRoot-instantie om het type te vergrendelen in plaats van het type zelf te vergrendelen, om deadlocks te voorkomen.

Deze dubbele controlevergrendeling lost de problemen van de concurrency op en voorkomt een exclusief slot bij elke aanroep van de eigenschapmethode Instance. Hiermee kunt u ook instantiatie uitstellen totdat het object voor het eerst wordt gebruikt. In de praktijk vereist een toepassing zelden dit type implementatie. In de meeste gevallen is de statische initialisatiebenadering voldoende.

Referentie: MSDN

Dankwoord

[Gamma95] Gamma, Helm, Johnson en Vlissides. Ontwerppatronen: elementen van herbruikbare objectgerichte software. Addison-Wesley, 1995.

[Lea99] Lea, Doug. Gelijktijdig programmeren in Java, tweede editie. Addison-Wesley, 1999.

[Sells03] Sells, Chris. "Sealed Sucks." sellsbrothers.com Nieuws. Beschikbaar op: http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 .

Singleton (PHP)

Voorbeeld van 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-ontwerppatroon (in het algemeen)

Opmerking: de singleton is een ontwerppatroon.
Maar het beschouwde ook een anti-patroon.

Het gebruik van een singleton moet vóór gebruik zorgvuldig worden overwogen. Er zijn meestal betere alternatieven.

Het grootste probleem met een singleton is hetzelfde als het probleem met globale variabelen. Ze introduceren externe wereldwijde veranderlijke toestand. Dit betekent dat functies die een singleton gebruiken niet alleen afhankelijk zijn van de invoerparameters, maar ook van de status van de singleton. Dit betekent dat testen ernstig kan worden gecompromitteerd (moeilijk).

De problemen met singletons kunnen worden beperkt door ze te gebruiken in combinatie met creatiepatronen; zodat de initiële creatie van de singleton kan worden gecontroleerd.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow