Quando dovresti usare il modello singleton invece di una classe statica?[Chiuso]

StackOverflow https://stackoverflow.com/questions/46541

  •  09-06-2019
  •  | 
  •  

Domanda

Indicare le considerazioni progettuali nel decidere tra l'uso di a singleton rispetto ad una classe statica.In questo modo, sei costretto a mettere in contrasto i due, quindi qualunque contrasto tu possa inventare è utile anche per mostrare il tuo processo di pensiero!Inoltre, a ogni intervistatore piace vedere esempi illustrativi.:)

È stato utile?

Soluzione

  • I singleton possono implementare interfacce ed ereditare da altre classi.
  • I single possono essere caricati pigramente.Solo quando effettivamente serve.Ciò è molto utile se l'inizializzazione include costosi caricamenti di risorse o connessioni al database.
  • I singleton offrono un oggetto reale.
  • I singleton possono essere estesi in una factory.La gestione degli oggetti dietro le quinte è astratta, quindi è più gestibile e si traduce in un codice migliore.

Altri suggerimenti

Che ne dici di "evitarli entrambi"?Singleton e classi statiche:

  • Può introdurre uno stato globale
  • Diventa strettamente associato a più altre classi
  • Nascondi dipendenze
  • Può rendere difficili le lezioni di test unitario in isolamento

Invece, esamina Iniezione di dipendenza E Inversione del contenitore di controllo biblioteche.Molte delle librerie IoC gestiranno la gestione della durata per te.

(Come sempre, ci sono delle eccezioni, come le classi matematiche statiche e i metodi di estensione C#.)

Direi che l'unica differenza è la sintassi:MySingleton.Current.Qualunque() vs MySingleton.Qualunque().Lo Stato, come ha menzionato David, in definitiva è “statico” in entrambi i casi.


MODIFICARE:La brigata bury è arrivata da Digg...comunque, ho pensato a un caso che richiederebbe un singleton.Le classi statiche non possono ereditare da una classe base né implementare un'interfaccia (almeno in .Net non possono).Quindi, se hai bisogno di questa funzionalità, devi utilizzare un singleton.

Una delle mie discussioni preferite su questo problema è Qui (sito originale inattivo, ora collegato a Internet Archive Wayback Machine.)

Per riassumere i vantaggi di flessibilità di un Singleton:

  • Un singleton può essere facilmente convertito in una fabbrica
  • Un singleton può essere facilmente modificato per restituire diverse sottoclassi
  • ciò può comportare un'applicazione più gestibile

Una classe statica con un carico di variabili statiche è un po' un trucco.

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

Un singleton con un'istanza reale è migliore.

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

Lo stato è presente SOLO nell'istanza.

Quindi il singleton può essere modificato in seguito per eseguire pooling, istanze thread-local ecc.E nessuno dei codici già scritti deve essere modificato per ottenere il vantaggio.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

È possibile fare qualcosa di simile con una classe statica ma ci sarà un sovraccarico per chiamata nell'invio indiretto.

Puoi ottenere l'istanza e passarla a una funzione come argomento.Ciò consente al codice di essere indirizzato al singleton "giusto".Sappiamo che te ne servirà solo uno...finché non lo fai.

Il grande vantaggio è che i singleton con stato possono essere resi thread-safe, mentre una classe statica non può, a meno che non la si modifichi per essere un singleton segreto.

Pensa a un singleton come a un servizio.È un oggetto che fornisce un insieme specifico di funzionalità.Per esempio.

ObjectFactory.getInstance().makeObject();

L'object factory è un oggetto che esegue un servizio specifico.

Al contrario, una classe piena di metodi statici è una raccolta di azioni che potresti voler eseguire, organizzate in un gruppo correlato (La classe).Per esempio.

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

L'esempio StringUtils qui è una raccolta di funzionalità che possono essere applicate ovunque.L'oggetto factory singleton è un tipo specifico di oggetto con una chiara responsabilità che può essere creato e distribuito dove richiesto.

Le classi statiche vengono istanziate in fase di esecuzione.Questo potrebbe richiedere molto tempo.I singleton possono essere istanziati solo quando necessario.

I singleton non dovrebbero essere utilizzati allo stesso modo delle classi statiche.In sostanza,

MyStaticClass.GetInstance().DoSomething();

è essenzialmente lo stesso di

MyStaticClass.DoSomething();

Quello che dovresti effettivamente fare è trattando il singleton come un altro oggetto.Se un servizio richiede un'istanza di tipo singleton, passa tale istanza al costruttore:

var svc = new MyComplexServce(MyStaticClass.GetInstance());

Il servizio non dovrebbe essere consapevole del fatto che l'oggetto è un singleton e dovrebbe trattarlo semplicemente come un oggetto.

L'oggetto può certamente essere implementato, come dettaglio di implementazione e come aspetto della configurazione complessiva, come singleton se ciò semplifica le cose.Ma le cose che usano l'oggetto non dovrebbero sapere se l'oggetto è un singleton o meno.

Se per "classe statica" intendi una classe che ha solo variabili statiche, allora in realtà possono mantenere lo stato.La mia comprensione è che l'unica differenza sarebbe il modo in cui accedi a questa cosa.Per esempio:

MySingleton().getInstance().doSomething();

contro

MySingleton.doSomething();

Gli interni di MySingleton saranno ovviamente diversi tra loro ma, a parte i problemi di sicurezza dei thread, entrambi funzioneranno allo stesso modo per quanto riguarda il codice client.

Il modello singleton viene generalmente utilizzato per servire dati statici o indipendenti dall'istanza in cui più thread possono accedere ai dati contemporaneamente.Un esempio possono essere i codici statali.

I singleton non dovrebbero mai essere usati (a meno che non si consideri una classe senza stato mutabile come singleton).Le "classi statiche" non dovrebbero avere uno stato modificabile, a parte forse cache thread-safe e simili.

Praticamente ogni esempio di singleton mostra come non farlo.

Se un singleton è qualcosa di cui puoi sbarazzarti, per ripulirlo, puoi considerarlo quando è una risorsa limitata (es.solo 1 di esso) che non ti serve sempre e che comporta un qualche tipo di costo di memoria o di risorse quando viene allocato.

Il codice di pulizia appare più naturale quando si dispone di un singleton, rispetto a una classe statica contenente campi di stato statici.

Il codice, tuttavia, apparirà più o meno lo stesso in entrambi i casi, quindi se hai ragioni più specifiche per chiederlo, forse dovresti approfondire.

I due possono essere abbastanza simili, ma ricorda che il vero Singleton deve farlo si essere istanziato (concesso, una volta) e quindi servito.Una classe di database PHP che restituisce un'istanza di mysqli non è realmente un Singleton (come alcuni lo chiamano), perché restituisce un'istanza di un'altra classe, non un'istanza della classe che ha l'istanza come membro statico.

Quindi, se stai scrivendo una nuova classe di cui prevedi di consentire solo un'istanza nel tuo codice, potresti anche scriverla come Singleton.Consideralo come scrivere una classe semplice e aggiungerla per facilitare il requisito di un'istanza singola.Se stai utilizzando la classe di qualcun altro che non puoi modificare (come mysqli), dovresti utilizzare una classe statica (anche se non riesci a prefissare la sua definizione con la parola chiave).

I singleton sono più flessibili, il che può essere utile nei casi in cui si desidera che il metodo Instance restituisca diverse sottoclassi concrete del tipo Singleton in base al contesto.

Le classi statiche non possono essere passate come argomenti;le istanze di un singleton possono essere.Come menzionato in altre risposte, fai attenzione ai problemi di threading con le classi statiche.

p.p

Un singleton può avere un costruttore e un distruttore.A seconda della lingua, il costruttore potrebbe essere chiamato automaticamente la prima volta che viene utilizzato il singleton o mai se il singleton non viene utilizzato affatto.Una classe statica non avrebbe tale inizializzazione automatica.

Una volta ottenuto un riferimento a un oggetto singleton, è possibile utilizzarlo come qualsiasi altro oggetto.Potrebbe non essere nemmeno necessario che il codice client sappia che utilizza un singleton se un riferimento al singleton è archiviato in precedenza:

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

Ciò ovviamente semplifica le cose quando si sceglie di abbandonare il modello Singleton a favore di un modello reale, come IoC.

Utilizza il modello singleton quando devi calcolare qualcosa in fase di esecuzione che, se potessi, calcoleresti in fase di compilazione, come le tabelle di ricerca.

Penso che un luogo in cui Singleton avrà più senso della classe statica è quando devi costruire un pool di risorse costose (come le connessioni al database).Non saresti interessato a creare il pool se nessuno li usa mai (la classe statica significa che farai il lavoro costoso quando la classe viene caricata).

Un singleton è anche una buona idea se si desidera forzare una memorizzazione nella cache efficiente dei dati.ad esempio, ho una classe che cerca le definizioni in un documento xml.Poiché l'analisi del documento può richiedere del tempo, ho impostato una cache di definizioni (utilizzo SoftReferences per evitare outOfmemeoryErrors).Se la definizione desiderata non è nella cache, eseguo la costosa analisi xml.Altrimenti restituisco una copia dalla cache.Poiché avere più cache significherebbe che potrei comunque dover caricare la stessa definizione più volte, ho bisogno di una cache statica.Scelgo di implementare questa classe come singleton in modo da poter scrivere la classe utilizzando solo membri dati normali (non statici).Ciò mi consente di creare comunque un'istanza della classe nel caso in cui ne avessi bisogno per qualche motivo (serializzazione, test unitario, ecc.)

Singleton è come un servizio, come già accennato.Pro è la sua flessibilità.Statico, beh, hai bisogno di alcune parti statiche per implementare Singleton.

Singleton ha un codice che si occupa dell'istanziazione dell'oggetto reale, il che può essere di grande aiuto se si verificano problemi di corsa.In una soluzione statica potrebbe essere necessario gestire problemi di corsa in più posizioni di codice.

Tuttavia, proprio come Singleton può essere costruito con alcune variabili statiche, potresti essere in grado di confrontarlo con "goto".Può essere molto utile per costruire altre strutture, ma devi davvero sapere come usarlo e non dovresti abusarne.Pertanto la raccomandazione generale è di attenersi a Singleton e di utilizzare static se necessario.

controlla anche l'altro post: Perché scegliere una classe statica rispetto a un'implementazione singleton?

fare riferimento Questo

riepilogo:

UN.Una semplice regola pratica che puoi seguire è che se non è necessario mantenere lo stato, puoi utilizzare una classe Static, altrimenti dovresti utilizzare un Singleton.

B.utilizzare un Singleton è se si tratta di un oggetto particolarmente “pesante”.Se il tuo oggetto è grande e occupa una quantità ragionevole di memoria, molte chiamate n/w (pool di connessioni) ... ecc.Per assicurarsi che non venga istanziata più volte.Una classe Singleton aiuterà a prevenire che un simile caso accada

Quando la singola classe ha bisogno di state.I singleton mantengono uno stato globale, le classi statiche no.

Ad esempio, creando un helper attorno a una classe di registro:Se hai un hive modificabile (HKey Current User vs.HKEY Local Machine) potresti andare:

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

Ora qualsiasi ulteriore chiamata a quel singleton funzionerà sull'hive della macchina locale.Altrimenti, utilizzando una classe statica, dovresti specificare che l'hive della macchina locale ogni volta o avere un metodo simile ReadSubkeyFromLocalMachine.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top