Domanda

Quando NON dovresti usare una classe singleton anche se potrebbe essere molto allettante farlo? Sarebbe molto bello se avessimo un elenco dei casi più comuni di "singletonite" che dovremmo evitare di evitare.

È stato utile?

Soluzione

Non utilizzare un singleton per qualcosa che potrebbe evolversi in una risorsa multipla.

Questo probabilmente suona sciocco, ma se dichiari qualcosa di singleton stai facendo una dichiarazione molto forte che è assolutamente unico. Stai costruendo il codice attorno ad esso, sempre di più. E quando poi scopri dopo migliaia di righe di codice che non è affatto un singleton, hai un'enorme quantità di lavoro davanti a te perché tutti gli altri oggetti si aspettano "il" oggetto sacro della classe WizBang per essere un singleton.

Esempio tipico: " C'è solo una connessione al database con questa applicazione, quindi è un singleton. " - Cattiva idea. Potresti voler avere diverse connessioni in futuro. Meglio creare un pool di connessioni al database e popolarlo con una sola istanza. Funziona come un Singleton, ma tutti gli altri codici avranno un codice coltivabile per accedere al pool.

EDIT: Capisco che teoricamente puoi estendere un singleton in più oggetti. Tuttavia, non esiste un ciclo di vita reale (come il pooling / unpooling), il che significa che non esiste una reale proprietà degli oggetti che sono stati distribuiti, vale a dire che ora il multi-singleton dovrebbe essere apolide per essere utilizzato contemporaneamente con metodi e thread diversi.

Altri suggerimenti

Beh, i singleton per la maggior parte stanno solo rendendo le cose statiche comunque. Quindi o stai effettivamente rendendo i dati globali, e sappiamo tutti che le variabili globali sono cattive o stai scrivendo metodi statici e non è molto OO, vero?

Qui è un resoconto più dettagliato sul perché i singoli siano cattivi, di Steve Yegge. Fondamentalmente non dovresti usare i singoli in quasi tutti i casi, non puoi davvero sapere che non sarà mai necessario in più di un posto.

So che molti hanno risposto con " quando ne hai più di " ;, ecc.

Dato che il poster originale voleva un elenco di casi in cui non dovresti usare Singletons (piuttosto che il motivo principale), entrerò in contatto con:

Ogni volta che lo usi perché non ti è permesso usare un globale!

Il numero di volte in cui ho avuto un ingegnere junior che ha usato un Singleton perché sapevano che non avevo accettato globalmente nelle recensioni di codice. Sembrano spesso scioccati quando faccio notare che tutto ciò che hanno fatto è stato sostituire un globale con un modello Singleton e hanno ancora un globale!

Sono colpevole di una grande qualche anno fa (per fortuna ho imparato la mia lezione da allora).

Quello che è successo è che sono entrato a far parte di un progetto di app desktop che si era convertito in .Net da VB6 ed era un vero casino. Cose come funzioni di 40 pagine (stampate) e nessuna struttura di classe reale. Ho creato una classe per incapsulare l'accesso al database. Non un livello di dati reale (ancora), solo una classe di base che un livello di dati reale potrebbe utilizzare. Da qualche parte ho avuto la brillante idea di rendere questa lezione un singleton. Ha funzionato bene per circa un anno e quindi abbiamo dovuto creare anche un'interfaccia web per l'app. Il singleton ha finito per essere un enorme collo di bottiglia per il database, poiché tutti gli utenti web hanno dovuto condividere la stessa connessione. Ancora una volta ... lezione imparata.

Guardando indietro, probabilmente in realtà è stata la scelta giusta per un breve periodo, dal momento che ha costretto gli altri sviluppatori a essere più disciplinati sull'uso e li ha resi consapevoli di problemi di scoping che non erano precedentemente un problema nel mondo VB6. Ma avrei dovuto cambiarlo dopo qualche settimana prima che ci fossimo accumulati troppo.

Ecco uno sfogo del mio amico Alex Miller ... Non elenca esattamente " quando NON dovresti usare un singleton " ma è un post completo, eccellente e sostiene che si dovrebbe usare un singleton solo in rari casi, se non del tutto.

I singleton sono praticamente sempre una cattiva idea e generalmente inutili / ridondanti poiché sono solo una semplificazione molto limitata di un modello decente.

Cerca come funziona l'iniezione delle dipendenze. Risolve gli stessi problemi, ma in un modo molto più utile - in effetti, trovi che si applica a molte più parti del tuo design.

Anche se puoi trovare le librerie DI là fuori, puoi anche lanciarne una di base tu stesso, è abbastanza facile.

Cerco di avere un solo singleton: un'inversione dell'oggetto controllo / servizio locator.

IService service = IoC.GetImplementationOf<IService>();

Una delle cose che tendono a renderlo un incubo è se contiene stato globale modificabile . Ho lavorato a un progetto in cui c'erano Singleton usati ovunque per cose che avrebbero dovuto essere risolte in un modo completamente diverso (passa strategie, ecc.) La "de-singletonificazione". è stato in alcuni casi una riscrittura importante di parti del sistema. Direi che nella maggior parte dei casi quando le persone usano un Singleton, è solo un b / c sbagliato, sembra bello in primo luogo, ma si trasforma in un problema soprattutto nei test.

Quando hai più applicazioni in esecuzione nella stessa JVM.

Un singleton è un singleton nell'intera JVM, non solo una singola applicazione. Anche se più thread o applicazioni sembrano creare un nuovo oggetto singleton, usano tutti lo stesso se eseguiti nella stessa JVM.

A volte, supponi che ci sarà solo una cosa, poi ti sbagli.

Esempio, una classe di database. Supponi che ti connetterai sempre e solo al database della tua app.

// Its our database! We'll never need another
class Database
{
};

Ma aspetta! Il tuo capo dice, collega ad un altro database di ragazzi. Supponiamo che tu voglia aggiungere phpbb al sito Web e che desideri sfruttare il suo database per integrare alcune delle sue funzionalità. Dovremmo creare un nuovo singleton o un'altra istanza di database? La maggior parte delle persone concorda sul fatto che sia preferita una nuova istanza della stessa classe, non vi è duplicazione del codice.

Preferiresti avere

Database ourDb;
Database otherDb;

rispetto al database copia-passato e crea:

// Copy-pasted from our home-grown database.
class OtherGuysDatabase
{
};

La pendenza scivolosa qui è che potresti smettere di pensare di creare una nuova istanza di classi e invece iniziare a pensare che sia giusto avere un tipo per ogni istanza.

Nel caso di una connessione (ad esempio), ha senso che non vorrai rendere la connessione stessa un singleton, potresti aver bisogno di quattro connessioni o potresti dover distruggere e ricreare la connessione un numero di volte.

Ma perché non accedi a tutte le tue connessioni attraverso una singola interfaccia (cioè gestione delle connessioni)?

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