Alcuni problemi con i singoli enum:
Impegnarsi in una strategia di attuazione
In genere, "singleton" si riferisce a una strategia di implementazione, non a una specifica API. È molto raro Foo1.getInstance()
dichiarare pubblicamente che restituirà sempre la stessa istanza. Se necessario, l'implementazione di Foo1.getInstance()
può evolversi, ad esempio, per restituire un'istanza per thread.
Con Foo2.INSTANCE
dichiariamo pubblicamente che questa istanza è l' istanza e non c'è alcuna possibilità di cambiarla. La strategia di implementazione di avere una singola istanza è esposta e impegnata.
Questo problema non è paralizzante. Ad esempio, Foo2.INSTANCE.doo()
può fare affidamento su un oggetto helper locale di thread per disporre effettivamente di 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 superclasse forzata Foo2
non ha nulla a che fare con ciò che Foo2
dovrebbe essere. Questo è un inquinamento per la gerarchia dei tipi della nostra applicazione. Se vogliamo davvero una super classe, di solito è una classe di applicazione, ma non possiamo,Foo2
la superclasse è fissa.
Foo2
eredita alcuni metodi di istanza divertenti come name(), cardinal(), compareTo(Foo2)
, che sono solo fonte di confusione per Foo2
gli utenti. Foo2
non può avere il proprio name()
metodo anche se tale metodo è desiderabile Foo2
nell'interfaccia di.
Foo2
contiene anche alcuni metodi statici divertenti
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. Un singleton di solito non dovrebbe avere comunque metodi statici pulbici (diversi dai getInstance()
)
serializzabilità
È molto comune che i singoli siano con stato. Questi singleton generalmente non dovrebbero essere serializzabili. Non riesco a pensare a nessun esempio realistico in cui abbia senso trasportare un singleton con stato da una VM a un'altra VM; un singleton significa "unico all'interno di una VM", non "unico nell'universo".
Se la serializzazione ha davvero senso per un singleton con stato, il singleton dovrebbe specificare in modo esplicito e preciso cosa significa deserializzare un singleton in un'altra VM in cui potrebbe già esistere un singleton dello stesso tipo.
Foo2
si impegna automaticamente in una strategia di serializzazione / deserializzazione semplicistica. Questo è solo un incidente in attesa di accadere. Se abbiamo un albero di dati che fa riferimento concettualmente a una variabile di stato Foo2
in VM1 at t1, attraverso la serializzazione / deserializzazione il valore diventa un valore diverso - il valore della stessa variabile di Foo2
in VM2 at t2, creando un bug difficile da rilevare. Questo bug non accadrà Foo1
silenziosamente all'inserializzabile .
Restrizioni alla codifica
Ci sono cose che possono essere fatte in classi normali, ma vietate in enum
classe. Ad esempio, l'accesso a un campo statico nel costruttore. Il programmatore deve stare più attento poiché lavora in una classe speciale.
Conclusione
Salvando su enum, salviamo 2 righe di codice; ma il prezzo è troppo alto, dobbiamo portare tutti i bagagli e le restrizioni degli enum, ereditiamo inavvertitamente "caratteristiche" dell'enum che hanno conseguenze indesiderate. L'unico presunto vantaggio - serializzabilità automatica - risulta essere uno svantaggio.