Recherche…


Remarques

Le motif de conception Singleton est parfois considéré comme " Anti-pattern ". Cela est dû au fait qu'il a des problèmes. Vous devez décider par vous-même si vous pensez qu’il convient de l’utiliser. Ce sujet a été discuté à plusieurs reprises sur StackOverflow.

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

Singleton (C #)

Les singletons sont utilisés pour garantir qu'une seule instance d'un objet est en cours de création. Le singleton ne permet de créer qu'une seule instance, ce qui signifie qu'il contrôle sa création. Le singleton est l'un des motifs de conception de Gang of Four et est un modèle de création .

Motif Singleton Thread-Safe

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 fournit l'implémentation suivante pour un singleton paresseux et sécurisé:

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)

Les singletons en Java sont très similaires à C #, car les deux langages sont orientés objet. Vous trouverez ci-dessous un exemple de classe singleton, où une seule version de l'objet peut être active pendant la durée de vie du programme (en supposant que le programme fonctionne sur un seul thread)

public class SingletonExample {

    private SingletonExample() { }

    private static SingletonExample _instance;

    public static SingletonExample getInstance() {

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

Voici la version sécurisée du thread de ce programme:

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 a également un objet appelé ThreadLocal , qui crée une instance unique d'un objet sur une base de thread par thread. Cela pourrait être utile dans les applications où chaque thread a besoin de sa propre version de l'objet

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

Voici également une implémentation Singleton avec enum (contenant un seul élément):

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

Toute implémentation de classe Enum garantit qu’il n’existe qu’une seule instance de chaque élément.

Bill Pugh Singleton Pattern

Bill Pugh Singleton Pattern est l'approche la plus utilisée pour la classe Singleton car elle ne nécessite pas de synchronisation

public class SingletonExample {

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

avec l'utilisation de la classe statique interne privée, le titulaire n'est pas chargé en mémoire tant que quelqu'un n'appelle pas la méthode getInstance. La solution de Bill Pugh est thread-safe et ne nécessite pas de synchronisation.


Il y a d'autres exemples de singleton Java dans la rubrique Singletons sous la balise de documentation Java.

Singleton (C ++)

Selon Wiki : En génie logiciel, le modèle singleton est un modèle de conception qui limite l'instanciation d'une classe à un objet.

Cela est nécessaire pour créer exactement un objet pour coordonner les actions sur le système.

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 exemple pratique en java

Cas d'utilisation réelle pour le modèle Singleton;

Si vous développez une application client-serveur, vous avez besoin d'une seule instruction de ConnectionManager , qui gère le cycle de vie des connexions client.

Les API de base dans ConnectionManager:

registerConnection : Ajoute une nouvelle connexion à la liste de connexions existante

closeConnection : ferme la connexion à partir de l'événement déclenché par le client ou le serveur

broadcastMessage : Parfois, vous devez envoyer un message à toutes les connexions client abonnées.

Je ne fournis pas une implémentation complète du code source, car l'exemple deviendra très long. Au plus haut niveau, le code sera comme ça.

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

Classe de serveur exemple:

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

Autres cas pratiques d'utilisation de Singletons:

  1. Gestion de ressources globales comme ThreadPool, ObjectPool, DatabaseConnectionPool etc.
  2. Des services centralisés tels que la Logging des données d'application avec différents niveaux de journalisation tels que DEBUG,INFO,WARN,ERROR etc.
  3. Global RegistryService où différents services sont enregistrés avec un composant central au démarrage. Ce service global peut servir de Facade pour l'application

C # Exemple: Singleton multithread

L'initialisation statique convient à la plupart des situations. Lorsque votre application doit retarder l'instanciation, utiliser un constructeur autre que celui par défaut ou effectuer d'autres tâches avant l'instanciation et travailler dans un environnement multithread, vous avez besoin d'une solution différente. Il existe toutefois des cas dans lesquels vous ne pouvez pas compter sur le Common Language Runtime pour garantir la sécurité des threads, comme dans l'exemple d'initialisation statique. Dans de tels cas, vous devez utiliser des fonctionnalités linguistiques spécifiques pour vous assurer qu'une seule instance de l'objet est créée en présence de plusieurs threads. L'une des solutions les plus courantes consiste à utiliser l'idiome Double-Check Locking [Lea99] pour empêcher les threads distincts de créer de nouvelles instances du singleton en même temps.

L'implémentation suivante permet à un seul thread d'entrer dans la zone critique, identifiée par le bloc de verrouillage, alors qu'aucune instance de Singleton n'a encore été créée:

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

Cette approche garantit qu'une seule instance est créée et uniquement lorsque l'instance est nécessaire. De plus, la variable est déclarée volatile pour garantir que l'affectation à la variable d'instance se termine avant que la variable d'instance soit accessible. Enfin, cette approche utilise une instance syncRoot pour verrouiller, plutôt que de verrouiller le type lui-même, pour éviter les blocages.

Cette approche de verrouillage par double vérification résout les problèmes de concurrence de threads tout en évitant un verrou exclusif dans chaque appel à la méthode de propriété Instance. Il vous permet également de retarder l’instanciation jusqu’à ce que l’objet soit d’abord accédé. En pratique, une application nécessite rarement ce type d'implémentation. Dans la plupart des cas, l'approche d'initialisation statique est suffisante.

Référence: MSDN

Remerciements

[Gamma95] Gamma, Helm, Johnson et Vlissides. Modèles de conception: éléments du logiciel orienté objet réutilisable. Addison-Wesley, 1995.

[Lea99] Lea, Doug. Programmation concurrente en Java, deuxième édition. Addison-Wesley, 1999.

[Sells03] Vend, Chris. "Sucks Suck." sellsbrothers.com Nouvelles. Disponible à l' adresse : http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 .

Singleton (PHP)

Exemple de 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 (en général)

Remarque: le singleton est un motif de conception.
Mais il a également considéré un anti-modèle.

L'utilisation d'un singleton doit être considérée avec soin avant utilisation. Il existe généralement de meilleures alternatives.

Le principal problème avec un singleton est le même que le problème avec les variables globales. Ils introduisent un état mutable global externe. Cela signifie que les fonctions qui utilisent un singleton ne dépendent pas uniquement des paramètres d'entrée, mais également de l'état du singleton. Cela signifie que les tests peuvent être gravement compromis (difficile).

Les problèmes avec les singletons peuvent être atténués en les utilisant conjointement avec les modèles de création; afin que la création initiale du singleton puisse être contrôlée.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow