Recent, v-ați aprofundat în modelul de design singleton , cum să îl implementați în Java și pentru ce este. Dar dacă vă spun că Java vine cu propriul singleton din cutie? Intrigat? Atunci hai să ne scufundăm.

Probabil că știți deja despre clasa Enum . Are o caracteristică specială de care ar trebui să fii conștient. Mai exact, Enum implementează modelul de design singleton. Această opțiune este aproape aceeași cu abordarea singleton care implică un domeniu public .

Singleton ca enumerare:


public enum Device {   
    PRINTER	
} 
    

Singleton ca variabilă publică:


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

Abordarea enum este mai compactă decât abordarea în câmp public, deoarece nu trebuie să scriem propria noastră implementare. Cel mai important, enumerarile nu au probleme cu serializarea.

Serializarea enumărilor funcționează diferit decât pentru obiectele obișnuite: numai valoarea numelui enumerației este serializată. În timpul deserializării, metoda este utilizată cu numele deserializat pentru a obține o instanță. În plus, enum vă poate proteja împotriva atacurilor de reflexie .

Veți afla mai multe despre reflecție în lecțiile din al doilea modul, unde vom explora API-ul Reflection .

Java interzice instanțiarea enumărilor - o limitare inclusă în implementarea metodei newInstance a clasei Constructor , care este adesea numită atunci când se creează obiecte prin reflecție.

Extras de cod din Constructor.newInstance . Folosit pentru a crea o enumerare :


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

Dezavantajele utilizării unei enumerari pentru a crea un singleton includ:

  • Lipsa inițializării leneșe, deoarece obiectul este creat imediat și inițializarea nu poate fi amânată.

  • Alte clase nu pot fi prelungite. Adică, în cazurile în care trebuie să moșteniți o altă clasă, nu va funcționa să utilizați o enumerare ca singleton. În astfel de cazuri, trebuie să apelăm la celelalte opțiuni de implementare deja familiare nouă: o metodă statică sau o variabilă publică.

  • Când utilizați enum ca singleton, puteți utiliza doar un câmp enum .


public enum Device extends Electricity { 
    PRINTER 
}
    

Acest cod ne va da o eroare de compilare:

Nu este permisă nicio clauză de extindere pentru enumerare

Dar dacă trebuie să implementăm o interfață, nu există nicio problemă, deoarece enum poate implementa interfețe:


public enum Device implements Electricity { 
    PRINTER 
}
    

Dacă nu trebuie să utilizați moștenirea, cel mai bine este să implementați modelul singleton prin enum . Nu suntem singurii care recomandă acest lucru – Joshua Bloch însuși face și el .

Această abordare de implementare vă oferă comoditate, compactitate, serializare imediată, protecție împotriva atacurilor de reflexie și unicitate - tot ceea ce are nevoie un singleton bun!