Il problema con i singleton statici non è lo stato globale di per sé. Il problema è che di solito vengono usati per cose losche - uno degli esempi più comuni è una connessione al database.
I singleton statici sono errati per un motivo principale: puoi ottenere un'istanza di una classe che il singleton esegue ovunque nell'applicazione, in qualsiasi classe, senza mai consentire a un utente di alcune classi di sapere che la dipendenza esiste realmente.
Ovviamente, puoi anche fare lo stesso anche quando non hai un singleton statico e in qualche modo stai seguendo l'iniezione di dipendenza, costruendo una dipendenza in luogo (invece di passarla). Ma di solito quando lo fai ti rendi conto molto prima che qualcosa non va bene (ancor più quando la dipendenza costruita segue rigorosamente l'iniezione di dipendenza e improvvisamente non vedi uno, ma come il 7% dinew
chiama per costruire il grafico dell'oggetto). Singleton dà l'impressione che sia effettivamente ok, mentre in alcuni casi non lo è.
Con le dipendenze nascoste, è sufficiente che tu esegua una funzione utilizzando un parametro stringa nella modalità di sviluppo (o come parte della tua suite di test delle unità). Questa funzione chiamerà improvvisamente il database di produzione perché utilizza internamente il singleton. Se la dipendenza era nota in anticipo (la dipendenza sarebbe passata nella funzione), probabilmente ti chiederesti perché la funzione ha bisogno di un database in primo luogo e stai più attento prima di chiamarla.
La cosa con Spring è che non risolverà i problemi di progettazione. Ma può rendere la costruzione di un progetto strongmente disaccoppiato (dove praticamente tutto viene passato come dipendenza) più facile da costruire eseguendo la sua magia e collegando le classi in base ad alcune regole.
Se recuperi classi di servizio e moduli da Spring (o qualsiasi altro tipo di classe), non dovrai più armeggiare con le fabbriche e gestire attentamente le tue istanze.
Per garantire che una cosa che dovrebbe esistere solo una volta esista effettivamente solo dopo aver configurato il framework e averlo impostato. E questo è fantastico. L'ovvio svantaggio è che è fatto in qualche modo e per i programmatori meno esperti che hanno poca o nessuna esperienza con il contenitore IoC la magia potrebbe essere off-puting (vedi Maledizione della conoscenza ).
Personalmente, sono in qualche modo in bilico se una struttura IoC completa è una buona o una cattiva cosa. Mi piace avere alcuni contenitori responsabili della gestione delle mie classi e della certezza dei loro scopi, ma non sono un grande fan di fare tutte queste configurazioni usando una sorta di configuratore XML. Preferisco new
ing delle classi me stesso, inserendo manualmente le istanze new
ed in un contenitore di scelta e quindi utilizzando sempre il contenitore per recuperarle nuovamente.
La parte manuale va solo in un modo, nel contenitore. Se ho una classe che richiede una dipendenza, la chiederò dal contenitore, cioè dovrò prima impostarla lì.