Quando dovresti usare il pattern singleton invece di una classe statica? [chiuso]


85

Assegna un nome alle considerazioni di progettazione per decidere tra l'uso di un singleton rispetto a una classe statica. In questo modo, sei un po 'costretto a contrastare i due, quindi qualsiasi contrasto che riesci a trovare è anche utile per mostrare il tuo processo di pensiero! Inoltre, a ogni intervistatore piace vedere esempi illustrativi. :)


una classe java non può essere statica a meno che non sia una classe interna
Harshana

1
Se lo stato dell'oggetto è importante, usa singleton, altrimenti usa una classe statica.
Levent Divilioglu

Risposte:


80
  • I singleton possono implementare interfacce ed ereditare da altre classi.
  • I singleton possono essere caricati in modo pigro. Solo quando è effettivamente necessario. È molto utile se l'inizializzazione include un costoso caricamento di risorse o connessioni al database.
  • I singleton offrono un oggetto reale.
  • I singleton possono essere estesi in una fabbrica. La gestione degli oggetti dietro le quinte è astratta, quindi è meglio gestibile e si traduce in un codice migliore.

2
Dai un'occhiata anche a questo link: codeofdoom.com/wordpress/2008/04/20/…
Amit

4
"I singleton possono essere caricati in modo lento": in C #, il costruttore statico viene chiamato solo la prima volta che si fa riferimento a un membro statico. In PHP, puoi usare il caricamento automatico per farlo funzionare solo la prima volta che viene utilizzata la classe.
mpen

Anche le inizializzazioni statiche di Java sono pigre. Nessun punto per i single lì.
MikeFHay

13

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

  • Può introdurre lo stato globale
  • Associati strettamente a più altre classi
  • Nascondi le dipendenze
  • Può rendere difficili le classi di unit test in isolamento

Invece, guarda in Dependency Injection e Inversion of Control Container libraries. Molte delle librerie IoC gestiranno la gestione della vita per te.

(Come sempre, ci sono eccezioni, come classi di matematica statica e metodi di estensione C #.)


1
Piccole lendini: le classi singleton sono compatibili con le tecniche di inserimento delle dipendenze (basta inserirle nelle loro classi dipendenti e non hanno bisogno di codificare nulla) - questo consente di deridere e testare isolatamente. Sono anche un modello di progettazione valido per la gestione di risorse note per essere limitate a livello di piattaforma. (L'esempio classico sono le stampanti che non hanno la gestione dei conflitti.)
cdleary

@cdleary - concordato; tuttavia, l'implementazione classica spesso lascia Singleton.getInstance () in tutta la codebase. I "singleton" per gestire risorse, cache, ecc. Possono essere implementati con POCO / POJO e framework di contenitori IoC che supportano la gestione della durata (registra il tipo come durata del contenitore e ogni risoluzione otterrà la stessa istanza).
TrueWill

9
Se vuoi dare ai tuoi Singleton una sepoltura adeguata, vai su singletonfuneralservice.com
TrueWill

1
Hide Dependenciespiccole informazioni su questo punto: puoi implementare il pattern Inversion of Control, ad esempio, usando Ninject . Ciò consente di utilizzare solo un'istanza di un tipo SingletonScopeassociandola a , il che significa che inietterà sempre la stessa istanza, ma la classe non sarà singleton.
LuckyLikey

8

Direi che l'unica differenza è la sintassi: MySingleton.Current.W Any () vs MySingleton.W Any (). Lo stato, come ha detto David, è in definitiva "statico" in entrambi i casi.


EDIT: La brigata di sepoltura è 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 usare un singleton.


7

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ò risultare in un'applicazione più manutenibile

5

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 è SOLO nell'istanza.

Quindi il singleton può essere modificato in seguito per eseguire operazioni di pooling, istanze locali di thread, 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 ne avrai bisogno solo uno ... finché non lo fai.

Il grande vantaggio è che i singleton con stato possono essere protetti dai thread, mentre una classe statica no, a meno che non venga modificata in modo che sia un singleton segreto.


4

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

ObjectFactory.getInstance().makeObject();

La 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 passato dove richiesto.


4

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


13
Anche i singleton sono istanziati in fase di esecuzione ...
ricorsivo

1
@recursive: la creazione di istanze Singleton può essere controllata.
Nikit Batale

3
forse una parola migliore sarebbe inizializzazione (piuttosto che istanziazione)
Marlon

3

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

MyStaticClass.GetInstance().DoSomething();

è essenzialmente lo stesso di

MyStaticClass.DoSomething();

Quello che dovresti fare in realtà è trattare il singleton come un altro oggetto . Se un servizio richiede un'istanza del tipo singleton, passare tale istanza nel costruttore:

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

Il servizio non dovrebbe essere consapevole del fatto che l'oggetto è un singleton e dovrebbe trattare l'oggetto come un semplice 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.


2

Se per "classe statica" intendi una classe che ha solo variabili statiche, 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 thread-safety, entrambi funzioneranno allo stesso modo per quanto riguarda il codice client.


2
I singleton sono essi stessi oggetti -> possono essere passati come argomenti.
Christian Klauser

2

Il pattern 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 di stato.


1

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

Praticamente qualsiasi esempio di singleton mostra come non farlo.


4
E le classi manager che controllano le risorse hardware? E le classi di file di registro?
RJFalconer

0

Se un singleton è qualcosa di cui puoi sbarazzarti, per ripulirlo, puoi considerarlo quando è una risorsa limitata (cioè solo 1 di essa) che non ti serve tutto il tempo e hai un qualche tipo di memoria o costo delle risorse quando viene allocato.

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

Il codice, tuttavia, avrà lo stesso aspetto in entrambi i casi, quindi se hai motivi più specifici per chiedere, forse dovresti elaborare.


0

I due possono essere abbastanza simili, ma ricorda che il vero Singleton deve essere esso stesso istanziato (concesso, una volta) e quindi servito. Una classe di database PHP che restituisce un'istanza di mysqlinon è realmente un Singleton (come lo chiamano alcune persone), 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. Immaginalo come scrivere una lezione semplice e aggiungerla per facilitare il requisito della singola istanza. Se stai usando la classe di qualcun altro che non puoi modificare (come mysqli), dovresti usare una classe statica (anche se non riesci a anteporre alla sua definizione la parola chiave).


0

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 di Singleton in base a un contesto.


0

Le classi statiche non possono essere passate come argomenti; istanze di un singleton possono essere. Come accennato in altre risposte, controlla i problemi di threading con classi statiche.

rp


0

Un singleton può avere un costruttore e un distruttore. A seconda della lingua, il costruttore può 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, può essere utilizzato come qualsiasi altro oggetto. Il codice client potrebbe non aver nemmeno bisogno di sapere che usa un singleton se un riferimento al singleton è memorizzato in precedenza su:

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

Questo ovviamente rende le cose più facili quando si sceglie di abbandonare il pattern Singleton a favore di un pattern reale, come IoC.


0

Usa il pattern singleton quando hai bisogno di calcolare qualcosa in fase di esecuzione che potresti calcolare in fase di compilazione se potessi, come le tabelle di ricerca.


0

Penso che un luogo in cui Singleton avrà più senso rispetto alla 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 usasse mai (la classe statica significa che fai il lavoro costoso quando la classe viene caricata).


0

Un singleton è anche una buona idea se vuoi forzare un caching efficiente dei dati. per 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 outOfemeoryErrors). 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 ancora dover caricare la stessa definizione più volte, ho bisogno di una cache statica. Ho scelto di implementare questa classe come singleton in modo da poter scrivere la classe utilizzando solo membri di dati normali (non statici). Ciò mi consente di creare comunque un'istanza della classe qualora ne avessi bisogno per qualche motivo (serializzazione, unit test, ecc.)


0

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

Singleton dispone del codice per la creazione di istanze dell'oggetto reale, che può essere di grande aiuto se si verificano problemi di corsa. In una soluzione statica potrebbe essere necessario affrontare i problemi di corsa in più posizioni di codice.

Tuttavia, 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 utilizzare statico se necessario.

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


0

riferisci questo

sommario:

un. Una semplice regola pratica che puoi seguire è che se non ha bisogno di mantenere lo stato, puoi usare una classe Static, altrimenti dovresti usare 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) ..etc. Per assicurarti che non venga istanziato più volte. Una lezione Singleton aiuterà a prevenire che il caso accada


-1

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

Ad esempio, creare un aiuto per 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 opererà sull'hive del computer locale. Altrimenti, usando una classe statica, dovresti specificare che Local Machine hive everytiem, o avere un metodo come ReadSubkeyFromLocalMachine.


1
Direi di non usare un singleton in questo modo ... È molto pericoloso mantenere gli stati persistenti, perché il chiamante successivo potrebbe dimenticare di impostare l'alveare e scrivere nel registro nell'hive sbagliato ... :-( Questo è probabilmente un esempio di uso improprio che fa pensare alle persone che i
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.