Du har for nylig dykket ned i singleton-designmønsteret , hvordan man implementerer det i Java, og hvad det er til. Men hvad hvis jeg fortæller dig, at Java kommer med sin egen singleton ud af æsken? fascineret? Så lad os dykke ind.

Du kender sikkert allerede til Enum-klassen . Den har en speciel funktion, som du bør være opmærksom på. Specifikt implementerer Enum singleton-designmønsteret. Denne mulighed er næsten den samme som singleton-tilgangen, der involverer et offentligt felt.

Singleton som enum:


public enum Device {   
    PRINTER	
} 
    

Singleton som en offentlig variabel:


public class Printer {   
    public static final Printer PRINTER = new Printer();   
    private Printer() {
    }
//…
}
    

Enum - tilgangen er mere kompakt end public-field-tilgangen, da vi ikke behøver at skrive vores egen implementering. Vigtigst af alt har enums ingen problemer med serialisering.

Serialisering af enums fungerer anderledes end for almindelige objekter: kun værdien af ​​enum-navnet serialiseres. Under deserialisering bruges metoden med det deserialiserede navn for at få en instans. Derudover kan enum beskytte dig mod reflektionsangreb .

Du lærer mere om refleksion i lektionerne i det andet modul, hvor vi vil udforske Reflection API .

Java forbyder instansiering af enums — en begrænsning indbygget i implementeringen af ​​Constructor -klassens newInstance- metode, som ofte kaldes, når man opretter objekter gennem refleksion.

Uddrag af kode fra Constructor.newInstance . Bruges til at oprette en enum :


if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
    

Ulemperne ved at bruge en enum til at skabe en singleton inkluderer:

  • Manglende doven initialisering, da objektet oprettes med det samme, og initialiseringen ikke kan forsinkes.

  • Andre klasser kan ikke forlænges. Det vil sige, at i tilfælde, hvor du skal arve en anden klasse, vil det ikke fungere at bruge en enum som singleton. I sådanne tilfælde skal vi vende os til de andre implementeringsmuligheder, vi allerede kender: en statisk metode eller en offentlig variabel.

  • Når du bruger enum som singleton, kan du kun bruge ét enum- felt.


public enum Device extends Electricity { 
    PRINTER 
}
    

Denne kode vil give os en kompileringsfejl:

Ingen forlængelsesklausul tilladt for enum

Men hvis vi skal implementere en grænseflade, er der ikke noget problem, da enum kan implementere grænseflader:


public enum Device implements Electricity { 
    PRINTER 
}
    

Hvis du ikke behøver at bruge arv, er det bedst at implementere singleton-mønsteret via enum . Vi er ikke alene om at anbefale dette - Joshua Bloch selv gør det også .

Denne implementeringstilgang giver dig bekvemmelighed, kompakthed, serialisering ud af boksen, beskyttelse mod refleksionsangreb og unikhed - alt hvad en god singleton har brug for!