Di recente hai approfondito il modello di progettazione singleton , come implementarlo in Java e a cosa serve. Ma cosa succede se ti dico che Java viene fornito con il proprio singleton pronto all'uso? Incuriosito? Allora tuffiamoci dentro.
Probabilmente conosci già la classe Enum . Ha una caratteristica speciale di cui dovresti essere a conoscenza. In particolare, Enum implementa il modello di progettazione singleton. Questa opzione è quasi la stessa dell'approccio singleton che coinvolge un campo pubblico .
Singleton come enum:
public enum Device {
PRINTER
}
Singleton come variabile pubblica:
public class Printer {
public static final Printer PRINTER = new Printer();
private Printer() {
}
//…
}
L' approccio enum è più compatto dell'approccio public-field, poiché non è necessario scrivere la propria implementazione. Ancora più importante, gli enum non hanno problemi con la serializzazione.
La serializzazione degli enum funziona in modo diverso rispetto agli oggetti ordinari: viene serializzato solo il valore del nome enum. Durante la deserializzazione, il metodo viene utilizzato con il nome deserializzato per ottenere un'istanza. Inoltre, enum può proteggerti dagli attacchi di riflessione .
Imparerai di più sulla riflessione nelle lezioni del secondo modulo, dove esploreremo l' API Reflection . |
Java proibisce la creazione di istanze di enum, una limitazione incorporata nell'implementazione del metodo newInstance della classe Constructor , che viene spesso chiamato durante la creazione di oggetti tramite reflection.
Estratto di codice da Constructor.newInstance . Utilizzato per creare un enum :
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
Gli svantaggi dell'utilizzo di un enum per creare un singleton includono:
-
Mancanza di inizializzazione pigra, poiché l'oggetto viene creato immediatamente e l'inizializzazione non può essere ritardata.
-
Altre classi non possono essere estese. Cioè, nei casi in cui è necessario ereditare un'altra classe, non funzionerà utilizzare un enum come singleton. In questi casi, dobbiamo rivolgerci alle altre opzioni di implementazione che ci sono già familiari: un metodo statico o una variabile pubblica.
-
Quando si utilizza enum come singleton, è possibile utilizzare solo un campo enum .
public enum Device extends Electricity {
PRINTER
}
Questo codice ci darà un errore di compilazione:
Ma se dobbiamo implementare un'interfaccia, non ci sono problemi, poiché enum può implementare interfacce:
public enum Device implements Electricity {
PRINTER
}
Se non è necessario utilizzare l'ereditarietà, è meglio implementare il modello singleton tramite enum . Non siamo i soli a consigliarlo, anche lo stesso Joshua Bloch .
Questo approccio all'implementazione offre praticità, compattezza, serializzazione pronta all'uso, protezione dagli attacchi di riflessione e unicità: tutto ciò di cui ha bisogno un buon singleton!
GO TO FULL VERSION