Perché l’implementazione di un pattern Singleton nel codice Java è (a volte) considerata un anti-pattern nel mondo Java?

Ho visto alcune persone in SO che commentavano che Singleton Pattern è un anti-modello. Voglio sapere perché?

analisi

Una ragione è che i singleton non sono facili da gestire con i test unitari. Non è ansible controllare l’istanziazione e per la loro stessa natura può mantenere lo stato tra le invocazioni.

Per questo motivo il principio dell’iniezione di dipendenza è popolare. Ogni class viene iniettata (configurata) con le classi che devono funzionare (piuttosto che derivare tramite accessori singleton) e quindi i test possono controllare quali istanze di class dipendente utilizzare (e fornire mock se necessario).

Strutture come Spring controlleranno il ciclo di vita dei loro oggetti e spesso creano singleton, ma questi oggetti vengono iniettati dai loro oggetti dipendenti dal framework. Pertanto, il codebase stesso non tratta gli oggetti come singleton.

per esempio piuttosto che questo (per esempio)

public class Portfolio { private Calculator calc = Calculator.getCalculator(); } 

iniettavi la calcolatrice:

 public class Portfolio { public Portfolio(Calculator c) { this.calc = c; } } 

Pertanto, l’object Portfolio non sa / si preoccupa di quante istanze del Calculator esistono. I test possono iniettare una Calculator fittizia che semplifica i test.

Concorrenza

Limitando te stesso a un’istanza di un object, le opzioni per il threading sono limitate. L’accesso all’object singleton potrebbe dover essere sorvegliato (ad es. Tramite sincronizzazione). Se è ansible mantenere più istanze di tali oggetti, è ansible adattare il numero di istanze ai thread in esecuzione e aumentare le capacità simultanee della base di codice.

La mia opinione personale è che viola il principio della singola responsabilità. Gli oggetti Singleton sono responsabili sia del loro scopo sia del controllo del numero di istanze prodotte che penso sia sbagliato.

Questo è il motivo per cui molte persone delegano il controllo a un object di fabbrica.

[Mutevole] Singleton è un anti-modello di un anti-modello.

Il significativo anti-pattern sottostante è lo stato globale (o stato ambientale). Con lo stato globale hai un grande blog di dipendenza attraverso il tuo programma. Ciò influisce sul testing, ma questa è solo una parte delle conseguenze di una ctriggers programmazione.

Stratificato su questo, Singleton aggiunge un livello di complessità completamente superfluo semplicemente dichiarando campi static mutevoli.

I singleton in quanto tali non sono necessariamente un anti-pattern, ma hanno solo pochi benefici e diventano un antipattern quando vengono usati in modo errato (cosa che accade spesso).

Spesso, i singleton non sono affatto singleton, ma “variabili globali mascherate”. Inoltre, spesso vengono utilizzati quando la proprietà “solo una istanza” non è in realtà un vantaggio. (che di nuovo è bilanciato dal fatto che molte volte l’implementazione è sbagliata allo stesso tempo).

In aggiunta a ciò, possono essere difficili da implementare con il multithreading in mente (spesso fatto in modo sbagliato o inefficiente), e perdono la maggior parte dei loro benefici se si vuole controllare la loro istanziazione.

Se vuoi avere il controllo sull’istanza, devi farlo manualmente a un certo punto nelle prime fasi del programma, ma potresti anche semplicemente creare un’istanza di un object normale e inoltrarla in seguito.
Se l’ordine di distruzione è di qualche preoccupazione, è necessario implementarlo manualmente. Un singolo object automatico nella funzione principale è tanto più semplice e pulito.

Ci sono molti requisiti che potresti avere sul singleton:

  1. inizializzazione pigra;
  2. corretto smaltimento;
  3. scoping (uno per thread, per esempio).

In genere, inoltre, avrai un sacco di singleton nella tua app e il pattern Singleton non consente il codice riutilizzabile. Quindi, se vuoi attuare tutte queste preoccupazioni per tutti i tuoi singleton, vedrai immediatamente la sua qualità anti-pattern .

Strano. Sembra che l’implementazione errata di un Singleton sia un “anti-pattern”, non lo stesso Singleton.

Penso che abbiamo dimenticato che ogni programma deve iniziare da qualche parte. Deve esserci un’implementazione concreta di ogni astrazione, e alla fine ogni dipendenza sarà risolta, o la tua app non sarebbe molto utile.

La maggior parte dei framework DI consente di creare un’istanza di class come Singleton, ma la gestisce solo per te. Se si sceglie di fare da soli, l’iniezione di un singleton non è un problema. Anche Singleton IS è testabile e, se stai usando DI per iniettarlo, non rende instabile una class.

IMO, come ogni altro modello là fuori (compresi DI e IoC) è uno strumento. A volte si adatta, a volte no.