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:

Nessuna clausola di estensione consentita per enum

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!