Ricerca…


Osservazioni

Il motivo di design Singleton è talvolta considerato come " Anti pattern ". Ciò è dovuto al fatto che ha alcuni problemi. Devi decidere da solo se pensi che sia appropriato usarlo. Questo argomento è stato discusso più volte su StackOverflow.

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

Singleton (C #)

I singleton vengono utilizzati per garantire che venga creata una sola istanza di un oggetto. Il singleton consente di creare solo una singola istanza di se stesso, il che significa che ne controlla la creazione. Il singleton è uno dei modelli di design Gang of Four ed è un modello creativo .

Pattern Singleton sicuro per thread

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 fornisce la seguente implementazione per un singleton pigro e sicuro per i thread:

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)

I singleton in Java sono molto simili a C #, poiché entrambi i linguaggi sono orientati agli oggetti. Di seguito è riportato un esempio di una classe singleton, in cui solo una versione dell'oggetto può essere attiva durante la vita del programma (supponendo che il programma funzioni su un thread)

public class SingletonExample {

    private SingletonExample() { }

    private static SingletonExample _instance;

    public static SingletonExample getInstance() {

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

Ecco la versione thread-safe di quel 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 ha anche un oggetto chiamato ThreadLocal , che crea una singola istanza di un oggetto su una base thread per thread. Questo potrebbe essere utile nelle applicazioni in cui ogni thread ha bisogno della propria versione dell'oggetto

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

Ecco anche un'implementazione di Singleton con enum (contenente un solo elemento):

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

Qualsiasi implementazione della classe Enum garantisce che esista solo un'istanza di ciascun elemento.

Bill Pugh Singleton Pattern

Bill Pugh Singleton Pattern è l'approccio più utilizzato per la classe Singleton in quanto non richiede la sincronizzazione

public class SingletonExample {

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

con l'utilizzo della classe statica interna privata il titolare non viene caricato in memoria finché qualcuno non chiama il metodo getInstance. La soluzione di Bill Pugh è thread-safe e non richiede sincronizzazione.


Esistono altri esempi di singleton Java nell'argomento Singleton sotto il tag della documentazione Java.

Singleton (C ++)

Come per Wiki : nell'ingegneria del software, il modello singleton è un modello di progettazione che limita l'istanziazione di una classe a un oggetto.

Questo è necessario per creare esattamente un oggetto per coordinare le azioni attraverso il sistema.

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

Esempio pratico Lazy Singleton in java

Casi di utilizzo della vita reale per il modello Singleton;

Se si sta sviluppando un'applicazione client-server, è necessario disporre di un'unica istruzione di ConnectionManager , che gestisce il ciclo di vita delle connessioni client.

Le API di base in ConnectionManager:

registerConnection : aggiunge una nuova connessione all'elenco esistente di connessioni

closeConnection : closeConnection la connessione dall'evento attivato dal client o dal server

broadcastMessage : alcune volte devi inviare un messaggio a tutte le connessioni client sottoscritte.

Non sto fornendo l'implementazione completa del codice sorgente poiché l'esempio diventerà molto lungo. Ad alto livello, il codice sarà come questo.

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 Server di esempio:

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

Altri casi di utilizzo pratico per Singletons:

  1. Gestione di risorse globali come ThreadPool, ObjectPool, DatabaseConnectionPool ecc.
  2. Servizi centralizzati come la Logging dati dell'applicazione con diversi livelli di registro come DEBUG,INFO,WARN,ERROR ecc
  3. Global RegistryService dove diversi servizi sono registrati con un componente centrale all'avvio. Questo servizio globale può fungere da Facade per l'applicazione

C # Esempio: Singleton multithread

L'inizializzazione statica è adatta alla maggior parte delle situazioni. Quando l'applicazione deve ritardare l'istanziazione, utilizzare un costruttore non predefinito o eseguire altre attività prima dell'istanziazione e lavorare in un ambiente con multithreading, è necessaria una soluzione diversa. Esistono tuttavia casi in cui non è possibile fare affidamento sul Common Language Runtime per garantire la sicurezza dei thread, come nell'esempio di Inizializzazione statica. In questi casi, è necessario utilizzare funzionalità linguistiche specifiche per garantire che venga creata una sola istanza dell'oggetto in presenza di più thread. Una delle soluzioni più comuni consiste nell'usare l'idioma Double-Check Locking [Lea99] per impedire a thread separati di creare nuove istanze del singleton contemporaneamente.

La seguente implementazione consente solo ad un singolo thread di entrare nell'area critica, che identifica il blocco di blocco, quando nessuna istanza di Singleton è stata ancora creata:

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

Questo approccio garantisce che venga creata una sola istanza e solo quando è necessaria l'istanza. Inoltre, la variabile è dichiarata volatile per garantire che l'assegnazione alla variabile di istanza venga completata prima che sia possibile accedere alla variabile di istanza. Infine, questo approccio utilizza un'istanza syncRoot da bloccare, piuttosto che bloccare il tipo stesso, per evitare deadlock.

Questo approccio di blocco a doppio controllo risolve i problemi di concomitanza di thread evitando un blocco esclusivo in ogni chiamata al metodo di proprietà Instance. Inoltre, consente di ritardare l'istanziazione fino a quando l'oggetto non viene accesso per la prima volta. In pratica, un'applicazione raramente richiede questo tipo di implementazione. Nella maggior parte dei casi, l'approccio di inizializzazione statica è sufficiente.

Riferimento: MSDN

Ringraziamenti

[Gamma95] Gamma, Helm, Johnson e Vlissides. Modelli di progettazione: elementi del software orientato agli oggetti riutilizzabile. Addison-Wesley, 1995.

[Lea99] Lea, Doug. Programmazione simultanea in Java, Seconda edizione. Addison-Wesley, 1999.

[Sells03] Sells, Chris. "Suck Sealed". sellsbrothers.com Notizie. Disponibile all'indirizzo: http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 .

Singleton (PHP)

Esempio da 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)

Modello Singleton Design (in generale)

Nota: il singleton è un motivo di progettazione.
Ma ha anche considerato un anti-modello.

L'uso di un singleton deve essere considerato attentamente prima dell'uso. Di solito ci sono alternative migliori.

Il problema principale con un singleton è lo stesso del problema con le variabili globali. Introducono lo stato mutabile globale esterno. Ciò significa che le funzioni che utilizzano un singleton non dipendono esclusivamente dai parametri di input ma anche dallo stato del singleton. Ciò significa che il test può essere gravemente compromesso (difficile).

I problemi con i singleton possono essere mitigati usandoli insieme ai pattern di creazione; in modo che la creazione iniziale del singleton possa essere controllata.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow