Cosa c'è di così brutto nei single? [chiuso]


1983

Il pattern Singleton è un membro interamente versato della GoF s' il libro di modelli , ma ultimamente sembra piuttosto orfano da parte del mondo degli sviluppatori. Uso ancora parecchi singleton, soprattutto per le lezioni di fabbrica , e mentre devi stare un po 'attento ai problemi del multithreading (come qualsiasi classe in realtà), non riesco a capire perché siano così terribili.

Stack Overflow sembra soprattutto supporre che tutti siano d'accordo sul fatto che i Singleton siano cattivi. Perché?

Supportare le risposte con " fatti, riferimenti o competenze specifiche "


6
Devo dire che l'utilizzo di un design singleton mi ha bruciato di recente mentre ho cercato di adattare il codice. Mentre lo faccio nel mio tempo libero, sono quasi troppo pigro per riflettere questo. Cattive notizie per la produttività.
Marcin,

71
Ci sono molti "svantaggi" nelle risposte, ma mi piacerebbe anche vedere alcuni buoni esempi di quando lo schema è buono, in contrasto con il cattivo ...
DGM,

50
Ho scritto un post sul blog sull'argomento alcuni mesi fa: jalf.dk/blog/2010/03/… - e lasciatemi dire semplicemente. Personalmente non riesco a pensare a una singola situazione in cui un singleton è la soluzione giusta. Ciò non significa che una tale situazione non esista, ma ... chiamarli rari è un eufemismo.
jalf

8
@AdamSmith non significa che si deve a, ma significa che è possibile accedere in quel modo. E se non hai intenzione di accedervi in ​​quel modo, allora ci sono poche ragioni per renderlo un singleton in primo luogo. Quindi il tuo argomento è effettivamente "non c'è nulla di male nel creare un singleton se non lo trattiamo come un singleton. Sì, fantastico. Anche la mia auto non inquina se non ci guido. Ma è più facile non acquisire una macchina in primo luogo.;) (divulgazione completa: in realtà non ho una macchina)
jalf

35
La parte peggiore di tutto questo argomento è che le persone che odiano i single raramente danno suggerimenti concreti su cosa usare invece. I collegamenti ad articoli di riviste e blog autopubblicati in tutto questo articolo SO, ad esempio, vanno avanti e avanti sul perché non usare i singleton (e sono tutti ottimi motivi), ma sono estremamente sottili nelle sostituzioni. Un sacco di lavaggi a mano, però. Quelli di noi che cercano di insegnare ai nuovi programmatori perché non usare i singleton non hanno molti buoni controesempi di terze parti a cui fare riferimento, solo esempi inventati. È stancante.
Ti Strga,

Risposte:


1294

Parafrasato da Brian Button:

  1. Sono generalmente utilizzati come istanza globale, perché è così male? Perché nascondi le dipendenze della tua applicazione nel tuo codice, invece di esporle attraverso le interfacce. Fare qualcosa di globale per evitare di passarlo in giro è un odore di codice .

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

  3. Essi causano intrinsecamente un accoppiamento stretto del codice . Ciò rende in molti casi falsificarli sotto test piuttosto difficili.

  4. Portano lo stato in giro per tutta la durata dell'applicazione. Un altro colpo ai test poiché è possibile che si verifichi una situazione in cui è necessario ordinare i test, il che è un grande no per i test unitari. Perché? Perché ogni test unitario dovrebbe essere indipendente dall'altro.


324
Sono in disaccordo con te. Poiché i commenti sono consentiti solo 600 caratteri, ho scritto un post sul blog per commentare questo, si prega di consultare il link qui sotto. jorudolph.wordpress.com/2009/11/22/singleton-considerations
Johannes Rudolph

61
Sul punto 1 e 4, penso che i singleton siano utili, e in effetti quasi perfetti per la memorizzazione nella cache dei dati (specialmente da un DB). L'aumento delle prestazioni supera di gran lunga le complessità coinvolte nei test unitari di modellazione.
Dai Bok,

56
@Dai Bok: "memorizzazione nella cache dei dati (specialmente da un DB)" usa il modello proxy per fare questo ...
paxos1977,

55
Caspita, ottime risposte. Probabilmente ho usato una formulazione troppo aggressiva qui, quindi tieni presente che stavo rispondendo a una domanda negativamente orientata. La mia risposta doveva essere un breve elenco degli "schemi anti" che si verificano a causa di un cattivo utilizzo di Singleton. Divulgazione completa; Anch'io uso i Singleton di volta in volta. Ci sono più domande poste in modo neutrale su SO che farebbero ottimi forum per quando Singletons può essere considerato una buona idea. Ad esempio, stackoverflow.com/questions/228164/…
Jim Burger,

21
Non sono così grandi per la memorizzazione nella cache in un ambiente multithread. Puoi facilmente sconfiggere una cache con più thread in lotta per una risorsa limitata. [mantenuto da un singleton]
monksy

449

I singoli risolvono un (e solo un) problema.

Contesa di risorse.

Se hai qualche risorsa che

( 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 è quello più grande. Non vuoi abbandonare solo un singolo file di registro. Vuoi svuotare, sincronizzare e chiuderlo correttamente. Questo è un esempio di una singola risorsa condivisa che deve essere gestita.

È raro che tu abbia bisogno di un singleton. Il motivo per cui sono cattivi è che si sentono come un globale e sono un membro pienamente pagato del libro GoF Design Patterns .

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


43
Anche l'hardware è un esempio giusto? I sistemi incorporati hanno un sacco di hardware che potrebbe usare singleton - o forse uno grande? <grin>
Jeff,

170
Completamente d'accordo. Ci sono molti discorsi determinati "questa pratica è cattiva" che fluttua senza alcun riconoscimento del fatto che la pratica possa avere il suo posto. Spesso, la pratica è solo "cattiva" perché viene spesso utilizzata in modo improprio. Non c'è nulla di intrinsecamente sbagliato nel modello Singleton purché sia ​​applicato in modo appropriato.
Damovisa,

53
I singleton reali, per principio, sono molto rari (e una coda di stampa non è certamente una, e nemmeno un file di registro - vedi log4j). Più spesso, l'hardware è un singleton per coincidenza piuttosto che per principio. Tutto l'hardware collegato a un PC è nella migliore delle ipotesi un singleton casuale (pensate a più monitor, mouse, stampanti, schede audio). Anche un rilevatore di particelle da 500 milioni di dollari è un singleton per coincidenza e vincoli di budget - che non si applicano al software, quindi: nessun singleton. Nelle telecomunicazioni, né il numero di telefono né il telefono fisico sono singoli (si pensi all'ISDN, al call center).
digitalarbeiter

23
L'hardware può avere solo un'istanza di una varietà di risorse, ma l'hardware non è software. Non c'è motivo per cui una singola porta seriale su una scheda di sviluppo debba essere modellata come Singleton. In effetti, modellarlo in questo modo renderà più difficile il porting sulla nuova scheda che ha due porte!
dash-tom-bang,

19
Quindi scriveresti due classi identiche, duplicando molto codice, solo per avere due singleton che rappresentano due porte? Che ne dici di usare solo due oggetti SerialPort globali? Che ne dici di non modellare l'hardware come classi? E perché dovresti usare i singoli, che implicano anche l'accesso globale? Vuoi che tutte le funzioni del tuo codice siano in grado di accedere alla porta seriale?
jalf

352

Alcuni snob di codifica li guardano come un globale glorificato. Allo stesso modo in cui molte persone odiano l' affermazione goto , ce ne sono altre che odiano l'idea di usare mai un globale . Ho visto diversi sviluppatori fare di tutto per evitare un globale perché hanno considerato di usarne uno come ammissione di fallimento. Strano ma vero.

In pratica il modello Singleton è solo una tecnica di programmazione che è una parte utile del tuo insieme di concetti. Di tanto in tanto potresti trovare la soluzione ideale e quindi usarla. Ma usarlo solo per vantarti di utilizzare un modello di progettazione è altrettanto stupido che rifiutarsi di usarlo perché è solo un globale .


17
Il fallimento che vedo in Singleton è che la gente li usa al posto dei globali perché sono in qualche modo "migliori". Il problema è (come lo vedo io), che le cose che Singleton porta in tavola in questi casi sono irrilevanti. (Construct-on-first-use è banale da implementare in un non-singleton, per esempio, anche se in realtà non sta usando il costruttore per farlo.)
dash-tom-bang

21
Il motivo per cui "noi" li guardiamo dall'alto in basso è che "noi" molto spesso li vediamo usati in modo sbagliato, e troppo spesso. "Noi" sappiamo che hanno il loro posto di causa.
Bjarke Freund-Hansen,

5
@Phil, hai dichiarato "di tanto in tanto potresti trovare che è la soluzione ideale e quindi usarla". Ok, quindi esattamente in quale caso troveremo utile un singleton?
Pacerier,

22
@Pacerier, quando sussistono tutte le seguenti condizioni: (1) hai solo bisogno di qualcosa, (2) devi passare quella cosa come argomento in un gran numero di chiamate di metodo, (3) sei disposto ad accettare un possibilità di dover riformattare un giorno in cambio di un'immediata riduzione delle dimensioni e della complessità del codice evitando di far passare la maledetta ovunque.
antinome,

18
Non credo che questo risponda a nulla, dice solo che "a volte potrebbe andare bene, altre volte potrebbe non farlo". OK, ma perché e quando? Cosa rende questa risposta più di un argomento di moderazione ?
Guildenstern,

219

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

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

I singoli non sono altro che lo stato globale. Lo stato globale lo rende in modo che i tuoi oggetti possano segretamente impadronirsi di cose che non sono dichiarate nelle loro API e, di conseguenza, i Singleton trasformano le tue API in bugiardi patologici.

Dove sono finiti tutti i Singletons Gone sottolinea che l'iniezione di dipendenza ha reso facile ottenere istanze per i costruttori che li richiedono, il che allevia il bisogno sottostante alla base dei Singletons cattivi e globali denunciati nel primo articolo.


8
Gli articoli di Misko sull'argomento sono la cosa migliore che lo circonda al momento.
Chris Mayer,

22
Il primo collegamento in realtà non risolve un problema con i singoli, ma presuppone piuttosto una dipendenza statica all'interno della classe. È possibile correggere l'esempio dato passando i parametri, ma usando ancora i singleton.
DGM,

17
@DGM: Esatto - in effetti, c'è una grande disconnessione logica tra la parte "logica" dell'articolo e la parte "Singletons sono la causa".
Harper Shelby,

1
L'articolo della carta di credito Misko è un esempio estremo di uso improprio di questo modello.
Alex

2
Leggendo il secondo articolo, i Singleton fanno effettivamente parte del modello di oggetti descritto. Tuttavia, invece di essere accessibili a livello globale, questi sono privati ​​degli oggetti Factory.
FruitBreak,

121

Penso che la confusione sia causata dal fatto che le persone non conoscono la vera applicazione del modello Singleton. Non posso sottolineare abbastanza. Singleton non è un modello per avvolgere i globi. Il modello Singleton deve essere utilizzato solo per garantire l' esistenza di una sola istanza di una determinata classe durante il runtime.

La gente pensa che Singleton sia malvagio perché lo sta usando per i globi. È a causa di questa confusione che Singleton è guardato in basso. Per favore, non confondere Singletons e globals. Se utilizzato per lo scopo a cui era destinato, otterrai benefici estremi dal modello Singleton.


20
Cos'è un'istanza disponibile in tutta l'app? Oh. Globale . "Singleton non è uno schema per avvolgere i globi" è ingenuo o fuorviante, poiché per definizione lo schema avvolge una classe attorno a un'istanza globale.
cao

26
Ovviamente sei libero di creare un'istanza della classe all'avvio dell'applicazione e di iniettare quell'istanza, attraverso un'interfaccia, in tutto ciò che la utilizza. L'implementazione non dovrebbe preoccuparsi che possa essercene solo una.
Scott Whitlock,

4
@Dainius: non c'è davvero, alla fine. Certo, non puoi sostituire arbitrariamente l'istanza con un'altra. (Ad eccezione di quei momenti che inducono il volto in cui lo fai . In realtà ho già visto dei setInstancemetodi prima.) Tuttavia, ciò non ha molta importanza: quel weenie che "aveva bisogno" di un singleton, inoltre, non sapeva qualcosa di spaventoso sull'incapsulamento o cosa c'è di sbagliato in stato globale mutevole, quindi ha utilmente (?) fornito setter per ogni. singolo. campo. (E sì, questo succede. Molto . Quasi ogni singolo singleton che io abbia mai visto in natura era mutevole in base al design, e spesso in modo imbarazzante.)
cHao

4
@Dainius: in larga misura, abbiamo già. "Preferire la composizione rispetto all'eredità" è ormai da un po 'di tempo. Tuttavia, quando l'ereditarietà è la soluzione migliore, sei ovviamente libero di usarla. Stessa cosa con singoli, globi, threading, gotoecc. Potrebbero funzionare in molti casi, ma francamente, "funziona" non è abbastanza - se vuoi andare contro la saggezza convenzionale, è meglio essere in grado di dimostrare come il tuo approccio è migliore delle soluzioni convenzionali. E devo ancora vedere un caso del genere per il modello Singleton.
cHao,

3
Per non parlare a vicenda, non sto parlando solo di un'istanza disponibile a livello globale. Ci sono molti casi per quello. Di cosa sto parlando (in particolare quando dico "maiuscola-S Singleton") è il modello Singleton di GoF, che incorpora quella singola istanza globale nella classe stessa, la espone tramite un getInstancemetodo chiamato in modo simile e impedisce l'esistenza di un seconda istanza. Francamente, a quel punto, si potrebbe anche non hanno nemmeno l' uno istanza.
cHao,

72

Una cosa piuttosto negativa dei single è che non puoi estenderli molto facilmente. Fondamentalmente devi costruire una sorta di motivo decorativo o qualcosa del genere se vuoi cambiare il loro comportamento. Inoltre, se un giorno vuoi avere più modi di fare quella cosa, può essere piuttosto doloroso cambiare, a seconda di come disponi il tuo codice.

Una cosa da notare, se usi i singleton, prova a passarli a chiunque ne abbia bisogno piuttosto che farli accedere direttamente ... Altrimenti se scegli di avere più modi di fare ciò 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 si chiami iniezione di dipendenza ed è generalmente considerato una buona cosa.

Come ogni schema però ... Pensaci e considera se il suo uso in una determinata situazione è inappropriato o no ... Le regole sono fatte per essere infrante di solito, e gli schemi non dovrebbero essere applicati volenti o nolenti senza pensarci.


17
Eh, se lo fai dappertutto, allora dovresti passare anche un riferimento al singelton ovunque, e quindi non hai più un singleton. :) (Che di solito è una buona cosa IMO.)
Bjarke Freund-Hansen,

2
@ BjarkeFreund-Hansen - Sciocchezze, di cosa stai parlando? Un singleton è semplicemente un'istanza di una classe che viene istanziata una volta. Fare riferimento a un tale Singleton non copia l'oggetto reale, ma semplicemente lo fa riferimento - hai ancora lo stesso oggetto (leggi: Singleton).
M. Mimpen,

2
@ M.Mimpen: No, un Singleton maiuscola (che è ciò di cui si sta discutendo qui) è un'istanza di una classe che (a) garantisce che esisterà solo un'istanza e (b) si accede tramite il proprio della classe punto di accesso globale integrato. Se hai dichiarato che nulla dovrebbe essere chiamato getInstance(), allora (b) non è più del tutto vero.
cHao,

2
@cHao Non ti seguo o non capisci a chi commento - che è di Bjarke Freund-Hansen. Bjarke afferma che avere diversi riferimenti a un singleton ha diversi singleton. Questo non è certamente vero poiché non ci sono copie in profondità.
M. Mimpen,

6
@ M.Mimpen: prendo il suo commento per riferirmi maggiormente all'effetto semantico. Una volta che il fuorilegge ti chiama getInstance(), hai effettivamente eliminato l'unica differenza utile tra il modello Singleton e un riferimento ordinario. Per quanto riguarda il resto del codice, la single non è più una proprietà. Solo il chiamante getInstance()deve mai sapere o preoccuparsi di quanti casi ci siano. Con un solo chiamante, per la classe costa più impegno e flessibilità per far valere in modo affidabile la semplicità rispetto al fatto che il chiamante memorizzi semplicemente un riferimento e lo riutilizzi.
cHao,

69

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

Anche i singoli sono un problema dal punto di vista dei test. Tendono a rendere difficili i test unitari isolati da scrivere. L'inversione del controllo (IoC) e l' iniezione delle dipendenze sono schemi intesi a superare questo problema in modo orientato agli oggetti che si presta a test unitari.

In un ambiente di immondizia , i singleton possono rapidamente diventare un problema per quanto riguarda la gestione della memoria.

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


4
so che è un filo di molti anni. ciao @Kimoz hai detto: - i singoli possono diventare rapidamente un problema per quanto riguarda la gestione della memoria. vorrei spiegare in modo più dettagliato quale tipo di problema potrebbe presentarsi per quanto riguarda la raccolta di rifiuti singoli e rifiuti.
Thomas

@Kimoz, La domanda è "Perché il modello singleton non è un problema in sé?" e hai semplicemente ripetuto il punto ma non hai fornito nemmeno un singolo caso d'uso valido del modello singleton.
Pacerier,

@Thomas, perché esiste un singleton per definizione in una sola istanza. Quindi, è spesso complesso assegnare l'unico riferimento a null. Può essere fatto, ma significa che controlli completamente il punto dopo il quale il singleton non viene utilizzato nella tua app. E questo è raro, e di solito piuttosto l'opposto di ciò che gli appassionati di singleton stanno cercando: un modo semplice per rendere sempre accessibile una singola istanza . Su alcuni framwork DI come Guice o Dagger, non è possibile liberarsi di un singleton e rimane per sempre nella memoria. (Sebbene i singleton forniti dai container siano molto migliori di quelli fatti in casa).
Snicolas,

54

Un singleton viene implementato utilizzando un metodo statico. I metodi statici sono evitati dalle persone che eseguono i test unitari perché non possono essere derisi o sradicati. La maggior parte delle persone su questo sito sono grandi sostenitori dei test unitari. La convenzione generalmente accettata per evitarli sta usando l' inversione del modello di controllo .


9
Questo suona più come un problema con il test unitario che può testare oggetti (unità), funzioni (unità), intere librerie (unità), ma fallisce con qualsiasi cosa statica in classe (anche unità).
v010dya,

2
non supponi di cogliere tutti i riferimenti esterni comunque? Se lo sei, allora qual è il problema per moc singleton, in caso contrario, stai davvero facendo unit test?
Dainius,

@Dainius: deridere le istanze è molto meno problematico delle classi deride. Si potrebbe presumibilmente estrarre la classe sotto test dal resto dell'applicazione e testare con una Singletonclasse falsa . Tuttavia, ciò complica immensamente il processo di test. Per uno, ora devi essere in grado di scaricare le classi a piacimento (non proprio un'opzione nella maggior parte delle lingue) o avviare una nuova macchina virtuale per ogni test (leggi: i test possono richiedere migliaia di volte il tempo). Per due, tuttavia, la dipendenza da Singletonè un dettaglio dell'implementazione che sta perdendo in tutti i test.
cHao,

Powermock può deridere roba statica.
Snicolas,

deridere un oggetto significa creare un oggetto reale? Se il deridere non crea un oggetto reale, allora perché importa se la classe è singleton o il metodo è statico?
Arun Raaj,

45

Anche i singoli sono cattivi quando si tratta di raggruppamento . Perché allora, non hai più "esattamente un singleton" nella tua applicazione.

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

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 tutto il database passa attraverso questo e solo SingletonDao. Il tuo ambiente di produzione ora appare così: Singleton

Finora tutto bene.

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

Molti singoli

Sembra strano, ma ora hai molti singoli nella tua applicazione . Ed è esattamente ciò che un singleton non dovrebbe essere: avere molti oggetti. Ciò è particolarmente negativo se, come mostrato in questo esempio, si desidera effettuare chiamate sincronizzate a un database.

Ovviamente questo è un esempio di un cattivo utilizzo di un singleton. Ma il messaggio di questo esempio è: non puoi fare affidamento sul fatto che esiste esattamente un'istanza di un singleton nella tua applicazione, specialmente quando si tratta di clustering.


4
se non sai come implementare singleton, non dovresti farlo. Se non sai cosa stai facendo, dovresti prima trovarlo, e solo dopo fare quello che ti serve.
Dainius,

3
Questo è interessante, ho una domanda. Quindi qual è esattamente il problema se i singleton - ognuno su una macchina / JVM diversa - si connettono a un singolo database? L'ambito Singletons è solo per quella particolare JVM, e ciò è vero anche in un cluster. Piuttosto che dire filosoficamente che questa particolare situazione è cattiva perché il nostro intento era un singolo oggetto attraverso l'applicazione, sarei felice di vedere eventuali problemi tecnici che possono sorgere a causa di questa disposizione.
Saurabh Patil,

39
  1. È facilmente (ab) utilizzato come variabile globale.
  2. Le classi che dipendono dai singoli sono relativamente più difficili da testare unitamente.

33

Il monopolio è il diavolo e i singoli con stato non di sola lettura / mutevole sono il problema "reale" ...

Dopo aver letto i Singleton sono bugiardi patologici, come suggerito nella risposta di Jason, mi sono imbattuto in questo piccolo bocconcino che fornisce l'esempio meglio presentato di come i singleton vengono spesso utilizzati in modo improprio.

Global è 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. I singoli senza stato (come le fabbriche) non sono un problema. I singoli con stato possono di nuovo rientrare in due categorie, quelli che sono immutabili o scrivono una volta e ne leggono molti (file di configurazione / proprietà). Questi non sono male. Singleton mutabili, che sono tipi di titolari di riferimento sono quelli di cui stai parlando.

Nell'ultima affermazione si riferisce al concetto del blog di "i single sono bugiardi".

Come si applica a Monopoli?

Per iniziare una partita di monopolio, prima di tutto:

  • stabiliamo prima le regole in modo che tutti siano sulla stessa pagina
  • a tutti viene dato un inizio uguale all'inizio del gioco
  • 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 nella migliore delle ipotesi ideali. Una sconfitta nel monopolio è difficile da inghiottire perché, il monopolio riguarda i soldi, se perdi devi guardare scrupolosamente il resto dei giocatori che finiscono il gioco, e le perdite sono di solito rapide e schiaccianti. Quindi, le regole di solito vengono distorte a un certo punto per servire l'interesse personale di alcuni giocatori a spese degli altri.

Quindi stai giocando a monopolio con gli amici Bob, Joe ed Ed. Stai rapidamente costruendo il tuo impero e consumando quote di mercato a un ritmo esponenziale. I tuoi avversari si stanno indebolendo e inizi a sentire l'odore del sangue (in senso figurato). Il tuo amico Bob ha investito tutti i suoi soldi nel bloccare il maggior numero possibile di proprietà di basso valore, ma il suo non sta ricevendo un elevato ritorno sugli investimenti come si aspettava. Bob, come un colpo di sfortuna, atterra sul tuo Boardwalk e viene eliminato dal gioco.

Ora il gioco passa dal lancio dei dadi amichevole agli affari seri. A Bob è stato fatto l'esempio del fallimento e Joe ed Ed non vogliono finire come "quel ragazzo". Quindi, essendo il protagonista, all'improvviso diventi nemico. Joe ed Ed iniziano a praticare scambi sotto il tavolo, iniezioni di denaro dietro la schiena, cambio di casa sottovalutato e in genere qualsiasi cosa per indebolirti come giocatore fino a quando uno di loro non sale in cima.

Quindi, invece di vincere uno di loro, il processo ricomincia da capo. All'improvviso, un insieme finito di regole diventa un bersaglio mobile e il gioco degenera nel tipo di interazioni sociali che costituirebbero la base di ogni programma 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'è nessuno che prenda le decisioni. Ogni giocatore nel gioco, a quel punto, sta facendo le proprie regole e il caos ne consegue fino a quando due dei giocatori non sono troppo stanchi per mantenere la sciarada e rinunciare lentamente.

Quindi, se un libro delle regole per un gioco rappresentasse accuratamente un singleton, il libro delle regole del monopolio sarebbe un esempio di abuso.

Come si applica alla programmazione?

A parte tutti gli ovvi problemi di sicurezza dei thread e di sincronizzazione che presentano singlet mutabili ... 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 di dati qui".

Personalmente, ho visto un programmatore abusare di un singleton utilizzandolo come una sorta di archivio contorto tra thread incrociati 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 testare in condizioni di "produzione". Certo, un sistema avrebbe potuto essere sviluppato utilizzando polling / signaling per superare alcuni dei problemi di prestazioni, ma ciò non risolverebbe i problemi con i test e, perché preoccuparsi quando un database "reale" può già realizzare la stessa funzionalità in un modo molto più robusto / modo scalabile.

Un Singleton è un'opzione solo se hai bisogno di ciò che fornisce un singleton. Un'istanza di sola lettura in scrittura di un oggetto. La stessa regola dovrebbe arrivare anche alle proprietà / ai membri dell'oggetto.


1
Cosa succede se singleton acquisisce alcuni dati?
Yola,

@Yola Ridurrebbe il numero di scritture se il singleton fosse programmato per l'aggiornamento su una pianificazione predeterminata e / o fissa, riducendo così la contesa del thread. Tuttavia, non saresti in grado di testare accuratamente il codice che interagisce con il singleton a meno che non deridi un'istanza non singleton che simula lo stesso utilizzo. La gente di TDD probabilmente avrebbe avuto una soluzione, ma avrebbe funzionato.
Evan Plaice,

@EvanPlaice: Anche con una finta, avresti alcuni problemi con il codice che dice Singleton.getInstance(). Un linguaggio che supporta la riflessione potrebbe essere in grado di aggirare il problema impostando il campo in cui è memorizzata One True Instance. I test IMO, tuttavia, diventano un po 'meno affidabili una volta che hai iniziato a dedicarti al monkeking con lo stato privato di un'altra classe.
cHao,

28

Singleton non riguarda la singola istanza!

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

  • Problema : Singleton può rappresentare una sfida nell'ambiente multi-thread
    Soluzione : Utilizzare un processo bootstrap a thread singolo per inizializzare tutte le dipendenze del proprio singleton.
  • Problema : è difficile deridere i singoli.
    Soluzione : utilizzare il metodo Modello di fabbrica per deridere

Puoi mappare MyModelsulla TestMyModelclasse che lo eredita, ovunque MyModelti verrà iniettato riceverai TestMyModelistruzioni. - Problema : i singoli possono causare perdite di memoria poiché non vengono mai eliminati.
Soluzione : eliminali! Implementa un callback nella tua app per smaltire correttamente i singoli, dovresti rimuovere tutti i dati ad essi collegati e infine: rimuoverli dalla Factory.

Come ho affermato nel titolo, singleton non riguarda la singola istanza.

  • Singletons migliora la leggibilità : puoi guardare la tua classe e vedere quale singleton ha iniettato per capire quali sono le sue dipendenze.
  • Singletons migliora la manutenzione : una volta rimossa una dipendenza da una classe, hai appena eliminato l'iniezione singleton, non è necessario andare a modificare un grande link di altre classi che hanno appena spostato la tua dipendenza (questo è un codice puzzolente per me @Jim Burger )
  • Singletons migliora la memoria e le prestazioni : quando succede qualcosa nella tua applicazione, e ci vuole una lunga catena di callback per consegnare, stai sprecando memoria e prestazioni, usando Singleton stai tagliando l'uomo intermedio e migliorando le tue prestazioni e l'utilizzo della memoria ( evitando allocazioni di variabili locali non necessarie).

2
Questo non affronta il mio problema principale con Singletons, ovvero che consentono l'accesso allo stato globale da una qualsiasi delle migliaia di classi del tuo progetto.
LegendLength

8
Quello sarebbe lo scopo ...
Ilya Gazman il

LegendLength Perché è sbagliato? Ad esempio, nella mia applicazione ho un Settingsoggetto singleton che è accessibile da qualsiasi widget in modo che ogni widget sappia come formattare i numeri visualizzati. Se non fosse un oggetto accessibile a livello globale, dovrei iniettarlo nel costruttore in ogni widget del costruttore e mantenere il riferimento ad esso come variabile membro. Questo è un terribile spreco di memoria e di tempo.
VK,

23

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

I due maggiori errori che vedo sono: trattarlo come un globale e non riuscire a definire la chiusura di Singleton.

Tutti parlano di Singleton come globali, perché in pratica lo sono. Tuttavia, gran parte (purtroppo, non tutta) della cattiveria in un globale non deriva intrinsecamente dall'essere globale, ma dal modo in cui la usi. Lo stesso vale per Singletons. In realtà più come "singola istanza" in realtà non deve significare "accessibile a livello globale". È più un sottoprodotto naturale e, dato tutto il male che sappiamo che ne deriva, non dovremmo avere tanta fretta di sfruttare l'accessibilità globale. Quando i programmatori vedono un Singleton sembrano accedervi sempre direttamente attraverso il suo metodo di istanza. Invece, dovresti accedervi come faresti con qualsiasi altro oggetto. La maggior parte del codice non dovrebbe nemmeno essere consapevole che si tratta di un Singleton (accoppiamento libero, giusto?). Se solo un po 'di codice accede all'oggetto come se fosse un globale, molti danni vengono annullati.

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

L'altro, meno comune, errore è ignorare lo stile di vita Singleton. Solo perché ce n'è solo uno non significa che Singleton sia un po 'onnipotente "lo è sempre stato e lo sarà sempre", né è generalmente desiderabile (gli oggetti senza un inizio e una fine violano tutti i tipi di ipotesi utili nel codice e dovrebbero essere impiegati solo nelle circostanze più disperate.

Se si evitano questi errori, Singletons può ancora essere un PITA, ma è pronto a vedere che molti dei problemi peggiori sono significativamente mitigati. Immagina un Java Singleton, che viene esplicitamente definito come una volta per classloader (il che significa che ha bisogno di una politica di sicurezza dei thread), con metodi di creazione e distruzione definiti e un ciclo di vita che detta quando e come vengono invocati, 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.

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


23

Vedi Wikipedia Singleton_pattern

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

Riferimenti (solo riferimenti pertinenti dall'articolo)

  1. ^ Alex Miller. Modelli che odio n. 1: Singleton , luglio 2007
  2. ^ Scott Densmore. Perché i single sono cattivi , maggio 2004
  3. ^ Steve Yegge. Singletons considerato stupido , settembre 2004
  4. ^ JB Rainsberger, IBM. Usa i tuoi singoli saggiamente , luglio 2001

8
Una descrizione del modello non spiega perché sia ​​considerato malvagio ...
Jrgns,

2
Difficilmente giusto: "È anche considerato un anti-modello da alcune persone, che ritengono che sia eccessivamente usato, introducendo limitazioni inutili in situazioni in cui non è richiesta una sola istanza di una classe". Guarda i riferimenti ... Comunque c'è RTFM per me.
GUI Junkie,

17

Non è che gli stessi singoli siano cattivi, ma lo è il modello di progettazione GoF. L'unico vero argomento valido è che il modello di progettazione GoF non si presta per quanto riguarda i test, soprattutto se i test vengono eseguiti in parallelo.

L'uso di una singola istanza di una classe è un costrutto valido purché si applichino i seguenti mezzi nel codice:

  1. Assicurarsi che la classe che verrà utilizzata come singleton implementa un'interfaccia. Ciò consente di realizzare stub o mock usando la stessa interfaccia

  2. Assicurarsi che Singleton sia thread-safe. Questo è un dato.

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

  4. Durante il runtime dell'applicazione, in cui è necessario passare i singleton a un determinato oggetto, utilizzare una factory di classe che costruisce quell'oggetto e fare in modo che la factory di classe 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 come la classe effettiva stessa o uno stub / mock che implementa il suo comportamento e passarlo così com'è alla classe che lo richiede. Non usare il fattore di classe che crea quell'oggetto sotto test che necessita del singleton durante il test poiché passerà la singola istanza globale di esso, il che vanifica lo scopo.

Abbiamo utilizzato Singletons nelle nostre soluzioni con un grande successo che è testabile garantendo un comportamento deterministico in flussi di test paralleli.


+1, infine una risposta che si rivolge quando un singleton può essere valido.
Pacerier,

16

Vorrei affrontare i 4 punti nella risposta accettata, spero che qualcuno possa spiegare perché mi sbaglio.

  1. Perché nascondere le dipendenze nel tuo codice è male? Esistono già dozzine di dipendenze nascoste (chiamate di runtime C, chiamate API del sistema operativo, chiamate di funzione globali) e le dipendenze singleton sono facili da trovare (cercare ad esempio ()).

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

    Se stai passando un oggetto attraverso 10 funzioni in uno stack di chiamate solo per evitare un singleton, è fantastico?

  2. Principio unico di responsabilità: penso che questo sia un po 'vago e dipende dalla tua definizione di responsabilità. Una domanda rilevante sarebbe: perché l'aggiunta di questa "responsabilità" specifica a una questione di classe?

  3. Perché passare un oggetto a una classe lo rende più strettamente accoppiato rispetto all'utilizzo di quell'oggetto come singleton all'interno della classe?

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

Per quanto riguarda i test unitari:

  • non tutte le classi devono essere testate in unità
  • non tutte le classi che devono essere testate in unità devono cambiare l'implementazione del singleton
  • se lo fanno necessario unità testato e hanno bisogno di cambiare l'implementazione, è facile cambiare una classe di utilizzare un Singleton ad avere il Singleton passata ad esso tramite l'iniezione di dipendenza.

1
1. Tutte quelle dipendenze nascoste? Anche quelli sono cattivi. Le dipendenze nascoste sono sempre malvagie. Ma nel caso del CRT e del sistema operativo, sono già lì e sono l'unico modo per fare qualcosa. (Prova a scrivere un programma C senza usare il runtime o il sistema operativo.) Questa capacità di fare cose supera di gran lunga i loro negativi. I singoli nel nostro codice non ottengono quel lusso; poiché sono saldamente all'interno della nostra sfera di controllo e responsabilità, ogni uso (leggi: ogni ulteriore dipendenza nascosta) dovrebbe essere giustificabile come l'unico modo ragionevole per fare cose. Molto, molto pochi di loro in realtà sono.
cHao,

2. La "responsabilità" è generalmente definita come "motivo per cambiare". Un singleton finisce per gestire la sua vita e fare il suo vero lavoro. Se si modifica la modalità di esecuzione del lavoro o la modalità di creazione del grafico a oggetti, è necessario modificare la classe. Ma se hai altro codice per creare il grafico a oggetti e la tua classe fa il suo vero lavoro, quel codice di inizializzazione può impostare il grafico a oggetti come preferisce. Tutto è molto più modulare e testabile, perché è possibile inserire doppi test e strappare tutto a piacimento, e non si fa più affidamento su parti mobili nascoste.
cHao,

1
@cHao: 1. È positivo che tu riconosca che la "capacità di fare cose supera di gran lunga i loro aspetti negativi". Un esempio potrebbe essere un framework di registrazione. È male imporre il passaggio di un oggetto di registrazione globale mediante iniezione di dipendenza attraverso livelli di chiamate di funzione se ciò significa che gli sviluppatori sono scoraggiati dalla registrazione. Quindi, singleton. 3. Il tuo stretto punto di accoppiamento è rilevante solo se desideri che i clienti della classe controllino il comportamento tramite polimorfismo. Questo non è spesso il caso.
Jon,

2
4. Non sono sicuro che "non può essere distrutto manualmente" è un'implicazione logica di "può essere solo un'istanza". Se è così che definisci singleton, allora non stiamo parlando della stessa cosa. Tutte le classi non devono essere testate in unità. Questa è una decisione aziendale e talvolta il time-to-market o il costo di sviluppo avranno la precedenza.
Jon,

1
3. Se non vuoi il polimorfismo, non hai nemmeno bisogno di un'istanza. Potresti anche renderlo una classe statica, perché ti stai legando a un singolo oggetto e comunque a una singola implementazione - e almeno allora l'API non ti sta mentendo tanto.
cHao,

15

Vince Huston ha questi criteri, che mi sembrano ragionevoli:

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

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

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


14

I single sono cattivi da un punto di vista purista.

Da un punto di vista pratico, un singleton è un compromesso tra tempo di sviluppo e complessità .

Se sai che la tua applicazione non cambierà molto, sono abbastanza OK. Sappi solo che potresti dover riformattare le cose se le tue esigenze cambiano in modo imprevisto (il che è abbastanza OK nella maggior parte dei casi).

I singleton a volte complicano anche i test unitari .


3
La mia esperienza è che iniziare con un singolo ti farà davvero male anche nel breve periodo, senza contare il lungo termine. Questo effetto potrebbe esserlo di meno se l'applicazione esiste già da qualche tempo e probabilmente è già infestata da altri singoli. Iniziando da zero? Evitali a tutti i costi! Vuoi una singola istanza di un oggetto? Lascia che una factory gestisca l'istanza di questo oggetto.
Sven,

1
AFAIK Singleton è un metodo di fabbrica. Quindi non ricevo la tua raccomandazione.
Tacone,

3
"A factory"! = "Un factory_method che non può essere separato dalle altre cose utili nella stessa classe"
Sven,

13

Non c'è nulla di intrinsecamente sbagliato nello schema, supponendo che sia usato per qualche aspetto del tuo modello che è veramente singolo.

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


6
Penso che il contraccolpo abbia più a che fare con le persone che praticano test unitari formalizzati rendendosi conto che sono un incubo da affrontare.
Jim Burger,

1
Non sono sicuro del perché questo sia -1. Non è la risposta più descrittiva, ma non ha nemmeno torto.
Programmatore fuorilegge il

13

Non commenterò l'argomento buono / cattivo, ma non li uso da quando è arrivata la primavera . L'uso dell'iniezione di dipendenza ha praticamente rimosso i miei requisiti per singleton, tecnici e fabbriche. Trovo questo un ambiente molto più produttivo e pulito, almeno per il tipo di lavoro che faccio (applicazioni web basate su Java).


3
non sono i fagioli di primavera, per impostazione predefinita, i single?
magro

3
Sì, ma intendo singleton "codificanti". Non ho "scritto un singleton" (cioè con un costruttore privato yada yada yada secondo il modello di progettazione) - ma sì, con la primavera sto usando una singola istanza.
prule,

4
quindi quando gli altri lo fanno, va bene (se lo userò dopo), ma se gli altri lo fanno e non lo userò, è male?
Dainius,

11

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

La parte negativa di un singleton è generalmente l'utente (o dovrei dire l'uso inappropriato di un singleton per cose che non è progettato per fare). L'autore del reato più grande sta usando un singleton come falsa variabile globale.


1
Grazie Loki :) Esattamente il mio punto. Tutta la caccia alle streghe mi ricorda il dibattito goto. Gli strumenti sono per le persone che sanno come usarli; usare uno strumento che non ti piace può essere pericoloso per te, quindi evitalo ma NON dire agli altri di non usare / non imparare a usarlo correttamente. Non sono esattamente "pro-singleton" ma mi piace il fatto di avere uno strumento del genere e di sentire dove è appropriato usarlo. Periodo.
dkellner,

8

Quando si scrive codice utilizzando singleton, ad esempio un logger o una connessione al database, e successivamente si scopre che è necessario più di un registro o più di un database, si è nei guai.

I single rendono molto difficile il passaggio da oggetti normali.

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

Invece di usare i singoli, è necessario passare tutti gli oggetti di utilità necessari da una funzione all'altra. Ciò può essere semplificato se li avvolgi tutti in un oggetto helper, in questo modo:

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

4
passare l'argomento per ogni metodo è geniale, dovrebbe andare almeno in 10 modi per inquinare il tuo API.
Dainius,

Questo è un ovvio svantaggio, che avrebbe dovuto essere gestito dalla lingua, per mezzo di argomenti che in qualche modo si propagano in chiamate nidificate, ma in assenza di tale supporto, deve essere fatto manualmente. Considera che anche i singleton naturali, come un oggetto che rappresenta l'orologio di sistema, hanno potenziali problemi. Ad esempio, in che modo coprirai il codice dipendente dall'orologio (pensa a un contatore elettrico a tariffa multipla) con i test?
Roman Odaisky,

dipende da cosa stai testando, se non stai testando singleton, perché ti preoccupi di come si comporta, se il tuo oggetto remoto 2 dipende da ogni altro comportamento, non è un problema singleton ..
Dainius,

Potresti fornire quale lingua si propagherà in chiamate nidificate?
Dainius,

1
Se hai un modulo che dipende da un altro e non lo sai / non riesci a parlarne, avrai difficoltà a prescindere dal fatto che sia singleton o no. Le persone usano l'ereditarietà spesso, dove dovrebbero usare la composizione, ma non dici che l'ereditarietà è cattiva e OOP dovrebbe essere evitato a tutti i costi, perché così tante persone stanno facendo errori di progettazione lì, o tu?
Dainius,

8

Il problema con i singoli è il problema di una maggiore portata e quindi dell'accoppiamento . Non si può negare che ci siano alcune situazioni in cui è necessario accedere a una singola istanza e ciò può essere realizzato in altri modi.

Ora preferisco progettare attorno a un contenitore di inversione di controllo (IoC) e consentire al ciclo di vita di essere controllato dal contenitore. Questo ti dà il vantaggio delle classi che dipendono dall'istanza di non essere a conoscenza del fatto che esiste una singola istanza. La durata del singleton può essere modificata in futuro. Una volta che un tale esempio che ho incontrato di recente è stato un facile adattamento da single thread a multi-thread.

FWIW, se si tratta di un PIA quando si tenta di testarlo, allora andrà in PIA quando si tenta di eseguire il debug, correggere un bug o migliorarlo.



7

I single non sono male. È negativo solo quando crei qualcosa di unico a livello globale che non è unico a livello globale.

Tuttavia, ci sono "servizi di ambito applicativo" (pensate a un sistema di messaggistica che fa interagire i componenti) - questo CHIAMA per un singleton, una "MessageQueue" - classe che ha un metodo "SendMessage (...)".

È quindi possibile effettuare le seguenti operazioni da ogni parte del luogo:

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

E, naturalmente, fai:

MessageQueue.Current.RegisterReceiver (questo);

nelle classi che implementano IMessageReceiver.


6
E se voglio creare una seconda coda di messaggi, con un ambito più piccolo, perché non dovrei essere autorizzato a riutilizzare il codice per crearlo? Un singleton lo impedisce. Ma se avessi appena creato una normale classe di coda messaggi e poi creato un'istanza globale per fungere da "ambito di applicazione", potrei creare una seconda istanza per un altro uso. Ma se rendi la classe un singleton, dovrei scrivere una seconda classe di coda messaggi.
jalf

1
Inoltre, perché non dovremmo semplicemente avere un CustomerOrderList globale in modo da poterlo chiamare facilmente da qualsiasi luogo come MessageQueue? Credo che la risposta sia la stessa per entrambi: sta effettivamente creando una variabile globale.
LegendLength

7

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


molte persone scrivono codice multi-thread non sicuro, ciò significa che dovremmo eliminare i thread?
Dainius,

@Dainius: in effetti sì. IMO il modello di concorrenza predefinito dovrebbe essere multi-processo, con un modo per due processi di (1) scambiarsi facilmente messaggi e / o (2) condividere la memoria secondo necessità. Il threading è utile se vuoi condividere tutto , ma non lo vuoi mai davvero. Potrebbe essere emulato condividendo l'intero spazio degli indirizzi, ma sarebbe anche considerato un anti-pattern.
cHao,

@Dainius: E, naturalmente, questo presuppone che sia necessaria la concorrenza onestà-bontà. Spesso tutto ciò che vuoi è poter fare una cosa mentre aspetti che il sistema operativo faccia qualcos'altro. (Ad esempio l'aggiornamento dell'interfaccia utente durante la lettura da un socket.) Un'API asincrona decente potrebbe rendere superfluo il threading completo nella stragrande maggioranza dei casi.
cao

quindi se hai un'enorme matrice di dati, che hai bisogno di processo, è meglio farlo in un singolo thread, perché per molte persone potrebbe farlo in modo sbagliato ..
Dainius,

@Dainius: in molti casi, sì. (Il threading potrebbe effettivamente rallentarti , se aggiungi la sincronizzazione al mix. Questo è un ottimo esempio del perché il multithreading non dovrebbe essere il primo pensiero della maggior parte delle persone.) In altri casi, sarebbe meglio avere due processi che condividono solo le cose necessarie. Ovviamente, dovresti disporre che i processi condividano la memoria. Ma francamente, lo vedo come una cosa buona , molto meglio, almeno, del default di condividere la modalità tutto. Richiede di dire esplicitamente (e quindi, idealmente, sapere) quali parti sono condivise e quindi quali parti devono essere thread-safe.
cHao,

6

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

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

I Singleton GoF al contrario degli IoC Singleton dovrebbero esporre "singletonity" nell'interfaccia attraverso il metodo getInstance (), e in modo che soffrano di tutto quanto detto sopra.


3
A mio avviso, "singletonity" è un dettaglio dell'ambiente di runtime e non dovrebbe essere considerato dal programmatore che ha scritto il codice di classe. Piuttosto, è una considerazione che deve essere fatta dall'UTENTE di classe. solo l'UTENTE sa quante istanze sono effettivamente richieste.
Earth Engine,

5

I single non sono cattivi, se lo usi correttamente e minimamente . Ci sono molti altri buoni modelli di design che a un certo punto sostituiscono le esigenze di singleton (e danno anche i migliori risultati). Ma alcuni programmatori non sono consapevoli di quei buoni schemi e usano il singleton per tutti i casi che rendono il singleton cattivo per loro.


Eccezionale! Sono completamente d'accordo! Ma potresti, e forse dovresti, elaborare molto di più. Come espandere quali schemi di progettazione sono più comunemente ignorati e come "singolarmente e minimamente" usare i singoli. Più facile a dirsi che a farsi ! : P
cregox,

Fondamentalmente l'alternativa è far passare oggetti attraverso i parametri del metodo, piuttosto che accedervi tramite lo stato globale.
LegendLength

5

In primo luogo, una classe e i suoi collaboratori devono innanzitutto svolgere lo scopo previsto anziché concentrarsi sulle persone a carico. La gestione del ciclo di vita (quando le istanze vengono create e quando escono dall'ambito di applicazione) non dovrebbe far parte della responsabilità delle classi. La migliore pratica accettata per questo è creare o configurare un nuovo componente per gestire le dipendenze usando l'iniezione delle dipendenze.

Spesso il software diventa più complicato, ha senso avere più istanze indipendenti della classe Singleton con stato diverso. Commettere codice per prendere semplicemente il singleton è sbagliato in questi casi. L'uso 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 considerata come un singleton, ma piuttosto dovrebbe essere un'applicazione del suo utilizzo o di come viene utilizzata per configurare le persone a carico. Per un modo rapido e sgradevole questo non ha importanza - solo la codifica dura dice che i percorsi dei file non contano ma per applicazioni più grandi tali dipendenze devono essere fattorizzate e gestite in modo più appropriato usando DI.

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


4

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


Se la tua classe non si limita a una sola istanza, avrai bisogno di membri statici nella tua classe gestiti da semafori che arrivano praticamente alla stessa cosa! Qual è la tua alternativa proposta?
Jeach,

Ho una grande applicazione con un "MainScreen" questa schermata apre molte finestre / moduli dell'interfaccia utente modali / non modali più piccoli. IMHO Sento che MainScreen dovrebbe essere un singleton, quindi ad esempio un widget da qualche parte in un angolo lontano dell'applicazione vuole mostrare il suo stato nella barra di stato del MainScreen, tutto ciò che deve fare è MainScreen.getInstance (). SetStatus ( "Some Text"); Cosa proponi in alternativa? Passa MainScreen su tutta l'applicazione ?? : D
Salvin Francis,

2
@SalvinFrancis: Quello che consiglierei è di smettere di avere oggetti a cui interessano cose di cui non dovrebbero preoccuparsi e di intrufolarsi nell'app per scherzare. :) Il tuo esempio sarebbe molto meglio fare con gli eventi. Quando si svolgono correttamente gli eventi, un widget non deve nemmeno preoccuparsi se esiste una schermata principale; trasmette semplicemente "ehi, cose accadute", e qualunque cosa si sia iscritta all'evento "cose ​​successe" (che si tratti di un MainScreen, un WidgetTest o qualcos'altro del tutto!) decide come vuole rispondere. È così che OOP dovrebbe essere fatto comunque. :)
cHao,

1
@Salvin Considera quanto è difficile ragionare su MainScreen quando esegui il debug se viene aggiornato 'silenziosamente' da molti componenti. Il tuo esempio è un motivo perfetto per cui i singoli sono cattivi.
LegendLength
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.