risposta-alla-domanda-sullo-sviluppo-web-bd.com

Cosa c'è di così male nei singleton?

Il singleton pattern è un membro completamente pagato del GoF 's pattern book , ma ultimamente sembra piuttosto orfano dal mondo degli sviluppatori. Uso ancora un bel po 'di singleton, specialmente per factory classes , e anche se devi stare un po' attento ai problemi del multithreading (come ogni classe in effetti), non riesco a capire perché sono così terribili.

Specialmente Overflow dello Stack sembra presumere che tutti siano d'accordo sul fatto che Singletons sia malvagio. Perché?

Supporta le tue risposte con " fatti, riferimenti o competenze specifiche "

1864
Ewan Makepeace

Parafrasato da Brian Button:

  1. Sono generalmente usati come istanze globali, perché è così brutto? Perché nascondi le dipendenze della tua applicazione nel codice, invece di esporle attraverso le interfacce. Fare qualcosa di globale per evitare di passarlo è a code smell .

  2. Essi violano il principio di responsabilità singola : in virtù del fatto che controllano la propria creazione e il proprio ciclo di vita.

  3. Costoro intrinsecamente fanno sì che il codice sia strettamente accoppiato . In molti casi ciò li rende falsi in fase di test.

  4. Portano lo stato in giro per tutta la vita dell'applicazione. Un altro successo per i test, dal momento che si può finire con una situazione in cui è necessario ordinare i test, che è un grande no no per i test unitari. Perché? Perché ogni test unitario dovrebbe essere indipendente dall'altro.

1223
Jim Burger

I single risolvono un problema (e uno solo).

Contesa risorse.

Se hai qualche risorsa

( 1 ) può avere solo una singola istanza, e

( 2 ) devi gestire quella singola istanza,

hai bisogno di un singleton .

Non ci sono molti esempi Un file di registro è il più grande. Non vuoi semplicemente abbandonare un singolo file di registro. Vuoi svuotare, sincronizzare e chiudere correttamente. Questo è un esempio di una singola risorsa condivisa che deve essere gestita.

È raro che tu abbia bisogno di un singleton. La ragione per cui sono cattivi è che si sentono come un globale e sono un membro completamente retribuito del GoF Design Patternsbook.

Quando pensi di aver bisogno di un globale, stai probabilmente commettendo un terribile errore di progettazione.

425
S.Lott

Alcuni snob di codice li guardano dall'alto come se fossero solo un glorioso globale. Allo stesso modo in cui molte persone odiano l'istruzione goto ci sono altri che odiano l'idea di usare sempre un global . Ho visto diversi sviluppatori fare di tutto per evitare un globale perché hanno considerato l'utilizzo di uno come ammissione di fallimento. Strano ma vero.

In pratica il modello Singleton è solo una tecnica di programmazione che è una parte utile del vostro kit di strumenti. Di volta in volta potresti scoprire che è la soluzione ideale e quindi usarla. Ma usarlo solo per vantare l'utilizzo di un pattern design è altrettanto stupido che rifiutarsi di usarlo mai perché è solo un global .

324
Phil Wright

Misko Hevery, di Google, ha alcuni articoli interessanti proprio su questo argomento ...

I single sono bugiardi patologici ha un esempio di test unitario che illustra come i singleton possono rendere difficile capire le catene di dipendenza e avviare o testare un'applicazione. È un esempio abbastanza estremo di abuso, ma il punto che egli fa è ancora valido:

I singleton non sono altro che uno stato globale. Lo stato globale lo rende in modo che i tuoi oggetti possano ottenere segretamente cose che non sono dichiarate nelle loro API e, di conseguenza, Singletons trasforma le tue API in bugiardi patologici.

Dove sono finiti tutti i Singletons fa capire che l'iniezione di dipendenza ha reso facile ottenere istanze a costruttori che li richiedono, il che allevia il bisogno di fondo dei cattivi Singleton globali decifrati nel primo articolo.

211
jason

Penso che la confusione sia causata dal fatto che le persone non conoscono la reale applicazione del modello Singleton. Non posso sottolineare abbastanza questo. Singleton è non un pattern per avvolgere globals. Il modello Singleton dovrebbe essere usato solo per garantire che una e una sola istanza di una data classe esista durante il tempo di esecuzione.

La gente pensa che Singleton sia malvagio perché lo stanno usando per i globals. È a causa di questa confusione che Singleton è guardato dall'alto in basso. Per favore, non confondere Singletons e Globali. Se utilizzato per lo scopo per il quale è stato concepito, otterrete benefici estremi dal modello Singleton.

111
Cem Catikkas

Una cosa piuttosto brutta dei singleton è che non è possibile estenderli molto facilmente. Fondamentalmente devi costruire un qualche tipo di pattern di decoratore o qualcosa del genere se vuoi cambiare il loro comportamento. Inoltre, se un giorno si desidera avere più modi di fare quella cosa, può essere piuttosto doloroso cambiare, a seconda di come si dispone il codice.

Una cosa da notare, se usi i singleton, prova a passarli a chiunque li abbia bisogno piuttosto che averli ad accedervi direttamente ... Altrimenti se decidessi di avere più modi di fare la cosa che Singleton fa, sarà piuttosto difficile da cambiare poiché ogni classe incorpora una dipendenza se accede direttamente al singleton.

Quindi in poche parole:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

piuttosto che:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

Credo che questo tipo di schema sia chiamato iniezione di dipendenza ed è generalmente considerato una buona cosa.

Come ogni modello però ... Pensaci e considera se il suo uso nella situazione data è inappropriato o no ... Le regole sono fatte per essere rotte di solito, e i modelli non dovrebbero essere applicati volenti o nolenti senza pensarci.

71
Mike Stone

Il modello singleton non è un problema in sé. Il problema è che il pattern è spesso usato da persone che sviluppano software con strumenti orientati agli oggetti senza avere una solida conoscenza dei concetti OO. Quando i singleton vengono introdotti in questo contesto tendono a crescere in classi ingestibili che contengono metodi di supporto per ogni piccolo uso.

I singleton sono anche un problema dal punto di vista dei test. Tendono a rendere difficili da scrivere i test unitari isolati.Inversion of control(IoC) einjection dependancesono pattern pensati per superare questo problema in un modo orientato agli oggetti che si presta al test unitario.

In un garbage collection environment singleton può diventare rapidamente un problema per quanto riguarda la gestione della memoria.

C'è anche lo scenario multi-thread in cui i singleton possono diventare un collo di bottiglia e un problema di sincronizzazione.

67
Kimoz

Un singleton viene implementato utilizzando un metodo statico. I metodi statici vengono evitati da persone che eseguono test unitari perché non possono essere derisi o soppressi. La maggior parte delle persone su questo sito sono grandi sostenitori dei test unitari. La convenzione generalmente più accettata per evitarli sta usando l'inversione di control pattern.

53
jwanagel

I singleton sono anche cattivi quando si tratta di clustering . Perché quindi, non hai più "esattamente un singleton" nella tua applicazione.

Si consideri la seguente situazione: come sviluppatore, è necessario creare un'applicazione Web che accede a un database. Per garantire che le chiamate simultanee al database non siano in conflitto tra loro, si crea un SingletonDao di thread-save:

public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

Quindi sei sicuro che esiste un solo singleton nella tua applicazione e tutti i database passano attraverso questo e solo SingletonDao. Il tuo ambiente di produzione ora si presenta così: Single Singleton

Tutto va bene finora.

Ora, considera di voler impostare più istanze della tua applicazione web in un cluster. Ora, improvvisamente hai qualcosa del genere:

Many singletons

Sembra strano, ma ora hai molti singleton nella tua applicazione . E questo è esattamente ciò che non dovrebbe essere un singleton: avere molti oggetti in esso. Ciò è particolarmente grave se tu, come mostrato in questo esempio, vuoi effettuare chiamate sincronizzate a un database.

Ovviamente questo è un esempio di cattivo utilizzo di un singleton. Ma il messaggio di questo esempio è: non si può contare sul fatto che esista esattamente un'istanza di un singleton nella propria applicazione, specialmente quando si parla di clustering.

44
Uooo
  1. È facilmente (ab) usato come variabile globale.
  2. Le classi che dipendono dai singleton sono relativamente più difficili da testare separatamente.
38
jop

Il monopolio è il diavolo e i singleton con stato non-readonly/mutable sono il problema 'reale' ...

Dopo aver letto I singleton sono bugiardi patologici come suggerito in la risposta di Jason mi sono imbattuto in questo piccolo bocconcino che fornisce l'esempio migliore presentato di how singletons sono spesso abusati.

Globale è male perché:

  • un. Causa conflitto nello spazio dei nomi
  • b. Espone lo stato in modo ingiustificato

Quando si tratta di Singletons

  • un. Il modo esplicito OO di chiamarli, previene i conflitti, quindi indica a. non è un problema
  • b. Singletons senza stato sono (come le fabbriche) non sono un problema. I single con stato possono di nuovo cadere in due categorie, quelli che sono immutabili o scrivono una volta e leggono molti (file di configurazione/proprietà). Questi non sono male. Singletons mutevoli, che sono i portatori di riferimento sono quelli di cui stai parlando.

Nell'ultima affermazione si riferisce al concetto del blog di 'singletons are liars'.

Come si applica a Monopoly?

Per iniziare una partita di monopolio, prima:

  • stabiliamo le regole prima in modo che tutti siano sulla stessa pagina
  • all'inizio del gioco tutti hanno una partenza uguale
  • viene presentato un solo insieme di regole per evitare confusione
  • le regole non possono cambiare durante il gioco

Ora, per chiunque non abbia veramente giocato al monopolio, questi standard sono ideali nel migliore dei casi. Una sconfitta in monopolio è difficile da inghiottire perché, il monopolio riguarda i soldi, se perdi devi guardare diligentemente il resto dei giocatori a terminare il gioco, e le perdite sono solitamente rapide e schiaccianti. Di conseguenza, le regole di solito vengono distorte a un certo punto per servire l'interesse personale di alcuni dei giocatori a scapito degli altri.

Quindi stai giocando al monopolio con gli amici Bob, Joe e Ed. Stai rapidamente costruendo il tuo impero e consumando quote di mercato ad un tasso esponenziale. I tuoi avversari si stanno indebolendo e inizi ad annusare il sangue (in senso figurato). Il tuo amico Bob ha messo tutti i suoi soldi nell'arresto di rete come molte proprietà di basso valore possibili, ma il suo non sta ricevendo un alto ritorno sugli investimenti nel modo in cui si aspettava. Bob, come un colpo di sfortuna, atterra sul tuo Boardwalk e viene eliminato dal gioco.

Ora il gioco passa dal lancio amichevole dei dadi a un business serio. Bob è stato reso l'esempio del fallimento e Joe e Ed non vogliono finire come "quel ragazzo". Quindi, essendo il giocatore principale tu, all'improvviso, diventi il ​​nemico. Joe e Ed iniziano a praticare mestieri sottobanco, iniezioni di denaro dietro le quinte, scambi di case sottovalutati e in generale qualsiasi cosa che ti indebolisca come giocatore finché uno di loro non sale in alto.

Quindi, invece di vincere uno di loro, il processo inizia dappertutto. All'improvviso, un insieme finito di regole diventa un bersaglio mobile e il gioco degenera nel tipo di interazioni sociali che costituirebbero le fondamenta di ogni reality show televisivo di alto livello dopo Survivor. Perché, perché le regole stanno cambiando e non c'è consenso su come/perché/cosa dovrebbero rappresentare e, cosa più importante, non c'è una sola persona che prende le decisioni. Ogni giocatore nel gioco, a quel punto, sta facendo le proprie regole e il caos si verifica fino a quando due dei giocatori sono troppo stanchi per mantenere la sciarada e lentamente arrendersi.

Quindi, se un regolamento per un gioco rappresentasse accuratamente un singleton, il regolamento di monopolio sarebbe un esempio di abuso.

Come si applica alla programmazione?

A parte tutti gli ovvi problemi di sicurezza e sincronizzazione dei thread che i singleton mutabili presentano ... Se si dispone di un set di dati, che è in grado di essere letto/manipolato da più origini diverse contemporaneamente ed esiste durante la vita dell'esecuzione dell'applicazione, è probabilmente un buon momento per fare un passo indietro e chiedere "sto usando il giusto tipo di struttura dati qui".

Personalmente, ho visto un programmatore abusare di un singleton usandolo come una sorta di archivio di database cross-thread contorto all'interno di un'applicazione. Avendo lavorato direttamente sul codice, posso attestare che è stato lento (a causa di tutti i blocchi di thread necessari per renderlo thread-safe) e un incubo su cui lavorare (a causa della natura imprevedibile/intermittente dei bug di sincronizzazione), e quasi impossibile da testare in condizioni di "produzione". Certo, un sistema potrebbe essere stato sviluppato utilizzando il polling/signaling per superare alcuni dei problemi di prestazioni ma che non risolverebbe i problemi con i test e, perché preoccuparsi quando un database "reale" può già realizzare la stessa funzionalità in un ambiente molto più robusto/modo scalabile.

Un Singleton è solo un'opzione se è necessario ciò che fornisce un singleton. Un'istanza di sola lettura di un oggetto. Quella stessa regola dovrebbe sovrapporsi anche alle proprietà/ai membri dell'oggetto.

30
Evan Plaice

Singleton non riguarda la singola istanza!

A differenza di altre risposte, non voglio parlare di ciò che è sbagliato in Singletons, ma per mostrarti quanto sono potenti e fantastici quando vengono usati correttamente!

  • Problema : Singleton può essere una sfida in ambiente multi-threading
    Soluzione : usa un processo di bootstrap a thread singolo per inizializzare tutte le dipendenze del singleton.
  • Problema : È difficile prendere in giro i singleton.
    Soluzione : utilizza il metodo Factory pattern per il mocking
    MyModel myModel = Factory.inject(MyModel.class); È possibile associare MyModel a TestMyModel class che lo eredita, ovunque quando MyModel verrà iniettato otterrete TestMyModel instread.
  • Problema : I singleton possono causare porri di memoria non eliminati.
    Soluzione : Bene, disponili! Implementa una richiamata nella tua app per disporre correttamente di un singletons, dovresti rimuovere tutti i dati ad essi collegati e infine: rimuoverli dalla Factory.

Come ho dichiarato al titolo Singleton non riguardano la singola istanza.

  • I singleton migliorano la leggibilità : puoi guardare la tua classe e vedere quale singleton ha iniettato per capire quali sono le sue dipendenze.
  • Singletons migliora la manutenzione : Dopo aver rimosso una dipendenza da una classe che hai appena cancellato qualche iniezione singleton, non devi andare a modificare un grosso link di altre classi che hanno semplicemente spostato la tua dipendenza (Questo è puzzolente codice per me @Jim Burger )
  • I singleton migliorano la memoria e le prestazioni : quando qualcosa accade nell'applicazione e richiede una lunga catena di callback da consegnare, stai sprecando memoria e prestazioni, utilizzando Singleton stai tagliando l'intermediario e migliorando le prestazioni e l'utilizzo della memoria (evitando allocazioni di variabili locali non necessarie).
22
Ilya Gazman

Vedi Wikipedia Singleton_pattern

È anche considerato un anti-modello da alcune persone, che sentono che è eccessivamente utilizzato, introducendo limitazioni inutili in situazioni in cui non è effettivamente richiesta una sola istanza di una classe. [1] [2] [3] [4]

Riferimenti (solo riferimenti pertinenti all'articolo)

  1. ^ Alex Miller. Modelli che odio # 1: Singleton , luglio 2007
  2. ^ Scott Densmore. Perché i singleton sono cattivi , maggio 2004
  3. ^ Steve Yegge. Singletons considerati stupidi , settembre 2004
  4. ^ J.B. Rainsberger, IBM. Usa saggiamente i tuoi singleton , luglio 2001
21
GUI Junkie

La mia risposta su come i singleton sono cattivi è sempre "sono difficili da fare bene". Molti dei componenti fondamentali delle lingue sono singleton (classi, funzioni, spazi dei nomi e persino operatori), così come le componenti in altri aspetti dell'informatica (localhost, route di default, filesystem virtuale, ecc.) E non è un caso. Mentre causano problemi e frustrazioni di tanto in tanto, possono anche far funzionare molte cose MOLTO meglio.

I due più grandi fallimenti che vedo sono: considerarli globali e non riuscire a definire la chiusura di Singleton.

Tutti parlano di Singleton come globals, perché fondamentalmente lo sono. Tuttavia, molto (purtroppo, non tutti) della cattiveria in un contesto globale non deriva intrinsecamente dall'essere globale, ma dal modo in cui lo si usa. Lo stesso vale per Singletons. In realtà più che "istanza singola" non ha realmente bisogno di "accessibile globalmente". È più un sottoprodotto naturale, e dato tutto il male che sappiamo proviene da esso, non dovremmo avere tanta fretta di sfruttare l'accessibilità globale. Una volta che i programmatori vedono un Singleton sembrano sempre accedervi direttamente attraverso il suo metodo di istanza. Invece, dovresti navigare ad esso come faresti con qualsiasi altro oggetto. La maggior parte del codice non dovrebbe nemmeno sapere che si tratta di un Singleton (accoppiamento lento, giusto?). Se solo un piccolo pezzetto di codice accede all'oggetto come se fosse globale, molti danni vengono annullati. Raccomando di applicarlo limitando l'accesso alla funzione di istanza.

Anche il contesto di Singleton è molto importante. La caratteristica distintiva di Singleton è che c'è "solo uno", ma la verità è che è "solo uno" all'interno di una sorta di contesto/spazio dei nomi. Di solito sono uno: uno per thread, processo, indirizzo IP o cluster, ma possono anche essere uno per processore, macchina, spazio dei nomi/caricatore di classe/qualsiasi, subnet, Internet, ecc.

L'altro, meno comune, errore è ignorare lo stile di vita di Singleton. Solo perché ce n'è uno solo non significa che Singleton sia un onnipotente "sempre era e sempre sarà", né è generalmente desiderabile (gli oggetti senza inizio e fine violano ogni tipo di ipotesi utili nel codice, e dovrebbero essere impiegati solo nella più disperata delle circostanze.

Se si evitano quegli errori, Singletons può ancora essere un PITA, ma è pronto per vedere che molti dei problemi peggiori sono significativamente mitigati. Immagina un Java Singleton, definito esplicitamente come una volta per classloader (il che significa che ha bisogno di un criterio di sicurezza del thread), con metodi definiti di creazione e distruzione e un ciclo di vita che determina quando e come vengono richiamati e il cui metodo "istanza" ha protezione del pacchetto in modo che sia generalmente accessibile tramite altri oggetti non globali. Ancora una potenziale fonte di problemi, ma sicuramente molto meno problemi.

Tristemente, piuttosto che insegnare buoni esempi di come fare Singletons. Insegniamo cattivi esempi, lasciamo che i programmatori li usino per un po 'e poi diciamo loro che sono un cattivo modello di progettazione.

21

Non è che gli stessi singleton siano cattivi, ma lo schema di progettazione di GoF è. L'unica vera argomentazione valida è che il modello di progettazione GoF non si presta a testare, specialmente se i test vengono eseguiti in parallelo.

L'utilizzo di una singola istanza di una classe è un costrutto valido se si applicano i seguenti mezzi nel codice:

  1. Assicurati che la classe che verrà utilizzata come singleton implementa un'interfaccia. Ciò consente di implementare stub o mock utilizzando la stessa interfaccia

  2. Assicurarsi che Singleton sia sicuro per i thread. Questo è un dato.

  3. Il singleton dovrebbe essere di natura semplice e non eccessivamente complicato.

  4. Durante il runtime dell'applicazione, dove i singleton devono essere passati a un determinato oggetto, utilizzare un class factory che costruisce quell'oggetto e fare in modo che la classe factory passi l'istanza singleton alla classe che ne ha bisogno.

  5. Durante il test e per garantire un comportamento deterministico, creare la classe singleton come istanza separata della classe stessa o di uno stub/mock che implementa il proprio comportamento e passarlo come è nella classe che lo richiede. Non utilizzare il fattore di classe che crea quell'oggetto sotto test che ha bisogno del singleton durante il test, in quanto passerà la singola istanza globale di esso, che sconfigge lo scopo.

Abbiamo utilizzato Singletons nelle nostre soluzioni con un grande successo che sono testabili garantendo un comportamento deterministico nei flussi di esecuzione paralleli.

16
user1578119

Mi piacerebbe affrontare i 4 punti della risposta accettata, si spera che qualcuno possa spiegare perché mi sbaglio.

  1. Perché le dipendenze nel codice sono nascoste? Esistono già dozzine di dipendenze nascoste (chiamate runtime C, chiamate API OS, chiamate a funzioni globali) e dipendenze singleton facili da trovare (cercare instance ()).

    "Fare qualcosa di globale per evitare di passarlo è un odore di codice." Perché non passa qualcosa in giro per evitare di renderlo un singleton un odore di codice?

    Se stai passando un oggetto attraverso 10 funzioni in una pila di chiamate solo per evitare un singleton, è così bello?

  2. Principio della singola responsabilità: penso che questo sia un po 'vago e dipende dalla vostra definizione di responsabilità. Una domanda pertinente sarebbe, perché aggiungere questa specifica "responsabilità" a una questione di classe?

  3. Perché passare un oggetto ad una classe lo rende più strettamente accoppiato che usare quell'oggetto come un singleton all'interno della classe?

  4. Perché cambia per quanto dura lo stato? I single possono essere creati o distrutti manualmente, quindi il controllo è ancora lì e puoi rendere la vita uguale a quella di un oggetto non singolo.

Per quanto riguarda i test unitari:

  • non tutte le classi devono essere testate da unità
  • non tutte le classi che devono essere testate su unità devono modificare l'implementazione del singleton
  • se hanno bisogno di essere testati unitamente a do e hanno bisogno di cambiare l'implementazione, è facile cambiare una classe dall'uso di un singleton per far passare il singleton tramite l'iniezione di dipendenza.
15
Jon

Vince Huston ha questi criteri, che mi sembrano ragionevoli:

Singleton deve essere considerato solo se tutti e tre i seguenti criteri sono soddisfatti:

  • La proprietà della singola istanza non può essere ragionevolmente assegnata
  • L'inizializzazione pigra è desiderabile
  • L'accesso globale non è altrimenti previsto

Se la proprietà della singola istanza, quando e come si verifica l'inizializzazione e l'accesso globale non sono problemi, Singleton non è sufficientemente interessante.

15
js.

Non ho intenzione di commentare l'argomento buono/cattivo, ma non li ho usati da Spring è arrivato. Usando l'iniezione di dipendenza ha praticamente rimosso i miei requisiti per singleton, servicelocators e factory. Trovo che questo sia un ambiente molto più produttivo e pulito, almeno per il tipo di lavoro che faccio (applicazioni web basate su Java).

13
prule

Non c'è nulla di intrinsecamente sbagliato nel modello, supponendo che venga usato per qualche aspetto del tuo modello che è veramente unico.

Credo che il contraccolpo sia dovuto al suo uso eccessivo che, a sua volta, è dovuto al fatto che è il modello più semplice da capire e implementare.

12
Ben Hoffstein

I singleton sono cattivi da un punto di vista purista.

Da un punto di vista pratico, un singleton è un trade-off in fase di sviluppo rispetto alla complessità .

Se sai che la tua applicazione non cambierà più di tanto, sono abbastanza OK con cui andare. Sappi solo che potrebbe essere necessario rifattorizzare le cose se le tue esigenze cambiano in modo inaspettato (il che è abbastanza OK nella maggior parte dei casi).

Talvolta anche i single possono complicare test unitari .

12
tacone

Singleton è un modello e può essere utilizzato o abusato come qualsiasi altro strumento.

La parte cattiva di un singleton è generalmente l'utente (o dovrei dire l'uso inappropriato di un singleton per cose che non è progettato per fare). Il più grande criminale sta usando un singleton come una variabile globale falsa.

11
Martin York

Quando scrivi codice usando singleton, ad esempio un logger o una connessione al database, e successivamente scopri che hai bisogno di più di un registro o più di un database, sei nei guai.

Singletons rende molto difficile spostarsi da loro a oggetti normali.

Inoltre, è troppo facile scrivere un singleton non thread-safe.

Piuttosto che usare singleton, dovresti passare tutti gli oggetti di utilità necessari dalla funzione alla funzione. Questo può essere semplificato se li avvolgi in un oggetto helper, come questo:

void some_class::some_function(parameters, service_provider& srv)
{
    srv.get<error_logger>().log("Hi there!");
    this->another_function(some_other_parameters, srv);
}
8
Roman Odaisky

Articolo recente su questo argomento di Chris Reath su Coding Without Comments .

Nota: la codifica senza commenti non è più valida. Tuttavia, l'articolo a cui è stato collegato è stato clonato da un altro utente.

http://geekswithblogs.net/AngelEyes/archive/2013/09/08/singleton-i-love-you-but-your-bringing-me-down-re-uploaded.aspx

7
David

I problemi con i singleton sono il problema dell'ampliamento dell'ambito e quindi l'accoppiamento . Non si può negare che ci sono alcune situazioni in cui è necessario accedere a una singola istanza, e può essere realizzato in altri modi.

Ora preferisco progettare attorno all'inversione del contenitore control (IoC) e permettere che la vita sia controllata dal container. Questo ti dà il vantaggio delle classi che dipendono dall'istanza per non essere consapevole del fatto che esiste una singola istanza. La vita del singleton può essere cambiata in futuro. Una volta che l'esempio che ho incontrato di recente è stato un adattamento semplice da singolo threaded a multi-threaded.

FWIW, se è un PIA quando provi a testare l'unità, allora va a PIA quando provi a eseguire il debug, correggere un bug o migliorarlo.

7
Mark Lindell

Ecco un'altra cosa sui singleton che nessuno ha ancora detto.

Nella maggior parte dei casi "singletonity" è un dettaglio di implementazione per alcune classi piuttosto che caratteristico della sua interfaccia. L'inversione del contenitore di controllo può nascondere questa caratteristica agli utenti della classe; devi solo contrassegnare la tua classe come un singleton (con l'annotazione @Singleton in Java per esempio) e basta; IoCC farà il resto. Non è necessario fornire accesso globale all'istanza Singleton perché l'accesso è già gestito da IoCC. Quindi non c'è niente di sbagliato in IoC Singletons.

GoF Singletons in opposizione a IoC Singletons dovrebbe esporre "singletonity" nell'interfaccia attraverso il metodo getInstance (), e così che essi soffrano di tutto quanto sopra detto.

6

Troppe persone mettono oggetti che non sono thread safe in un modello singleton. Ho visto esempi di un DataContext ( LINQ to SQL ) fatto in uno schema singleton, nonostante il fatto che DataContext non sia thread-safe ed è puramente un oggetto unit-of-work.

6
Aaron Powell

I singleton NON sono male. È solo brutto quando si crea qualcosa di unico a livello globale che non è globalmente unico.

Tuttavia, esistono "servizi di ambito applicativo" (si pensi a un sistema di messaggistica che interagisce con i componenti) - questo CHIAMATA per un singleton, una "MessageQueue" - classe che ha un metodo "SendMessage (...)".

È quindi possibile eseguire quanto segue da dappertutto:

MessageQueue.Current.SendMessage (new MailArrivedMessage (...));

E, naturalmente, fare:

MessageQueue.Current.RegisterReceiver (questo);

nelle classi che implementano IMessageReceiver.

6

Poiché sono fondamentalmente variabili globali orientate agli oggetti, in genere puoi progettare le tue classi in modo tale da non averne bisogno.

4
Ycros

Un modello emerge quando diverse persone (o gruppi) arrivano a soluzioni simili o identiche. Un sacco di persone usano ancora singoletti nella loro forma originale o usando modelli di fabbrica (una buona discussione in Modern C++ Design di Alexandrescu). La concorrenza e la difficoltà nella gestione della vita dell'oggetto sono i principali ostacoli, con il primo facilmente gestibile come suggerito.

Come tutte le scelte, Singleton ha la sua giusta quota di alti e bassi. Penso che possano essere usati con moderazione, specialmente per gli oggetti che sopravvivono alla durata delle applicazioni. Il fatto che siano simili (e probabilmente lo sono) a livello globale ha presumibilmente innescato i puristi.

4
user22044

Singleton non sono male, se lo usi correttamente & minimally . Ci sono molti altri buoni modelli di progettazione che sostituiscono le esigenze di Singleton ad un certo punto (e anche i migliori risultati). Ma alcuni programmatori non sono consapevoli di questi buoni modelli e usano il singleton per tutti i casi che rendono il singleton il male per loro.

4
Sriram

In primo luogo, una classe e i suoi collaboratori dovrebbero in primo luogo svolgere gli scopi previsti piuttosto che concentrarsi sui deoendenti. La gestione del ciclo di vita (quando le istanze sono creared snd quando escono dal campo di applicazione) non dovrebbe far parte della responsabilità di cladses. La best practice accettata per questo è creare o configurare un nuovo componente per gestire le dipendenze mediante l'integrazione delle dipendenze.

Spesso il software diventa più complicato ha senso avere più istanze indipendenti della classe "singleton" con stato differente. In questi casi, commettere codice per afferrare semplicemente il singleton è sbagliato. L'uso di Singleton.getInstance () potrebbe essere ok per piccoli sistemi semplici, ma non funziona/scala quando si potrebbe aver bisogno di un'istanza diversa della stessa classe.

Nessuna classe dovrebbe essere pensata come un singleton, ma piuttosto dovrebbe essere un'aplicazione del suo utilizzo o di come è usata per configurare i dipendenti. Per una cosa veloce e antipatica non importa - solo luke hardcoding dice che i percorsi dei file non contano, ma per le applicazioni più grandi tali dipendenze devono essere prese in considerazione e gestite in modo più appropriato usando DI.

I problemi che singleton causano nei test sono un sintomo del loro caso/ambiente di utilizzo singolo codificato. La suite di test e i numerosi test sono individuali e separano qualcosa che non è compatibile con un codificatore hardcoding.

4
mP.

Il Singleton - l'anti-pattern! di Mark Radford (Overload Journal # 57 - Oct 2003) è una buona lettura del perché Singleton è considerato un anti-modello. L'articolo discute anche di due approcci progettuali alternativi per sostituire Singleton.

3
Frank Grimm

Questo è quello che penso manchi dalle risposte finora:

Se hai bisogno di un'istanza di questo oggetto per lo spazio degli indirizzi del processo (e sei sicuro che questo requisito non cambierà), dovresti renderlo un singleton.

Altrimenti, non è un singleton.

Questo è un requisito molto strano, quasi mai di interesse per l'utente. I processi e l'isolamento dello spazio di indirizzamento sono dettagli di implementazione. Hanno un impatto solo sull'utente quando vogliono interrompere l'applicazione utilizzando kill o Task Manager.

Oltre alla creazione di un sistema di memorizzazione nella cache, non ci sono molti motivi per cui sei così sicuro che ci dovrebbe essere solo su istanza di qualcosa per processo. Che ne dici di un sistema di registrazione? Potrebbe essere meglio per questo essere per-thread o più a grana fine in modo da poter tracciare l'origine dei messaggi in modo più automatico. Che ne dici della finestra principale dell'applicazione? Dipende; forse vorrete che tutti i documenti dell'utente siano gestiti dallo stesso processo per qualche motivo, nel qual caso ci sarebbero più "finestre principali" in quel processo.

3
Daniel Earwicker

Alcuni contrappunti dell'autore:

Sei bloccato se hai bisogno di rendere la classe non singola in futuro Niente affatto - Ero in questa situazione con una singola connessione al database Singleton che volevo trasformare in un pool di connessioni. Ricorda che ogni singleton è accessibile tramite un metodo standard:

MyClass.instance

Questo è simile alla firma di un metodo di fabbrica. Tutto ciò che ho fatto è stato aggiornare il metodo di istanza per restituire la connessione successiva dal pool - non sono necessarie altre modifiche. Sarebbe stato molto più difficile se NON avessimo usato un singleton.

I singleton sono solo fantastici globals Non posso discuterne, ma lo sono anche tutti i campi e i metodi statici - tutto ciò a cui si accede dalla classe piuttosto che un'istanza è essenzialmente globale e non vedo così tanti pushback sull'uso di statici campi?

Non dicendo che i Singletons sono buoni, semplicemente respingendo alcuni dei "saperi convenzionali" qui.

3
Ewan Makepeace

Sfoca la separazione delle preoccupazioni .

Supposto che tu abbia un singleton, puoi chiamare questa istanza da qualsiasi punto della tua classe. La tua classe non è più pura come dovrebbe essere. La tua classe ora non opererà più sui suoi membri e sui membri che riceve esplicitamente. Ciò creerà confusione, perché gli utenti della classe non sanno quali siano le informazioni sufficienti di cui la classe ha bisogno. L'intera idea di encapsulation è di nascondere il metodo di un metodo agli utenti, ma se nel metodo si usa un singleton, si dovrà conoscere lo stato del singleton per usare correttamente il metodo. Questo è anti - OOP .

2
Graviton

Fuori dalla mia testa:

  1. Fanno rispettare l'accoppiamento stretto. Se il tuo singleton risiede su un Assembly diverso rispetto al suo utente, l'Assembly using non può mai funzionare senza l'Assembly che contiene il singleton.
  2. Consentono le dipendenze circolari, ad esempio, l'assembly A può avere un singleton con una dipendenza dall'assembly B e l'assembly B può utilizzare il singleton di Assembly A. Tutto senza rompere il compilatore.
1
Jon Limjap