Alcuni problemi con enum singletons:
Impegno per una strategia di implementazione
In genere, "singleton" si riferisce a una strategia di implementazione, non a una specifica API. È molto raro che Foo1.getInstance()
dichiari pubblicamente che restituirà sempre la stessa istanza. Se necessario, l'implementazione di Foo1.getInstance()
può evolvere, ad esempio, per restituire un'istanza per thread.
Con Foo2.INSTANCE
dichiariamo pubblicamente che questa istanza è l'istanza e non c'è possibilità di cambiarla. La strategia di implementazione di avere una singola istanza è esposta e impegnata a.
Questo problema non è paralizzante. Ad esempio, Foo2.INSTANCE.doo()
può contare su un oggetto helper locale del thread, per efficace avere un'istanza per-thread.
Estensione della classe Enum
Foo2
estende una super classe Enum<Foo2>
. Di solito vogliamo evitare le super classi; specialmente in questo caso, la super classe forzata su Foo2
non ha nulla a che fare con ciò che Foo2
dovrebbe essere. Questo è un inquinamento per la gerarchia di tipi della nostra applicazione. Se vogliamo davvero una super classe, di solito è una classe di applicazione, ma non possiamo, la super classe di Foo2
è fissa.
Foo2
eredita alcuni divertenti metodi di istanza come name(), cardinal(), compareTo(Foo2)
, che confondono solo gli utenti di Foo2
. Foo2
non può avere il proprio metodo name()
anche se quel metodo è desiderabile nell'interfaccia Foo2
.
Foo2
contiene anche alcuni divertenti metodi statici
public static Foo2[] values() { ... }
public static Foo2 valueOf(String name) { ... }
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
che sembra essere privo di senso per gli utenti. Solitamente un singleton non dovrebbe avere metodi statici pulbic (tranne il getInstance()
)
serializzabilità
È molto comune che i singleton abbiano uno stato. Questi singleton generalmente dovrebbero non essere serializzabili. Non riesco a pensare ad alcun esempio realistico in cui abbia senso trasportare un singleton stateful da una VM ad un'altra VM; un singleton significa "unico all'interno di una VM", non "unico nell'universo".
Se la serializzazione ha realmente senso per un singleton stateful, il singleton dovrebbe specificare in modo esplicito e preciso cosa significa deserializzare un singleton in un'altra VM in cui potrebbe esistere già un singleton dello stesso tipo.
Foo2
si impegna automaticamente in una semplicistica strategia di serializzazione / deserializzazione. Questo è solo un incidente che aspetta di accadere. Se abbiamo un albero di dati che fa riferimento concettualmente a una variabile di stato di Foo2
in VM1 in t1, attraverso la serializzazione / deserializzazione il valore diventa un valore diverso - il valore della stessa variabile di Foo2
in VM2 in t2, creando un hard per rilevare bug. Questo bug non avverrà in modo silenzioso per Foo1
unserializable.
Restrizioni di codifica
Ci sono cose che possono essere fatte nelle classi normali, ma vietate nelle classi enum
. Ad esempio, accedere a un campo statico nel costruttore. Il programmatore deve essere più attento dal momento che sta lavorando in una classe speciale.
Conclusione
Facendo piggyback su enum, salviamo 2 righe di codice; ma il prezzo è troppo alto, dobbiamo trasportare tutti i bagagli e le restrizioni delle enumerazioni, inavvertitamente ereditiamo "caratteristiche" di enum che hanno conseguenze non volute. L'unico presunto vantaggio - la serializzabilità automatica - risulta essere uno svantaggio.