Così come promesso nel precedente articolo, in seguito alla soluzione proposta dallo stimato Marco Carlini, voglio mantenere la parola e scrivere questo articolo sul cache management.
Per chi non avesse letto il mio precedente articolo sulla Business Delegate, il problema evidenziato era dato dal fatto che veniva adottata l’onerosa Reflection per istanziare a runtime le classi di Business.
La soluzione proposta da Marco è stata quella di adottare un sistema di Chache Management per memorizzare, una volta istanziate, le classi di Business così da risparmiare le risorse almeno nei richiami successivi.
Trovandoci in ambito J2EE e avendo sfruttato il framework web Struts, la prima cosa venuta in mente per mettere, passatemi il termine “la pezza”
, è stata quella di inserire queste classi nella Session, ma… da sempre ho trovato inserire oggetti in session come mettere in uno sgabuzzino tutti gli oggetti a cui non sappiamo trovare una sistemazione e quando dobbiamo andare a ritrovarli… ahi… che sorprese.
Oltre che poco nobile come soluzione, per trovarne una degna di tale nome, mi sono posto le seguenti domande:
Inserire gli oggetti in session è una soluzione di sicuro semplice, nel momento in cui stiamo inserendo il valore, ma è altrettanto semplice quando (e per chi) la si vuole ritrovare?
Mettiamo il caso che stiamo lavorando con un’applicazione Java, come un’Applet, non avendo sessioni, come possiamo memorizzare i dati e mantenerli persistenti?
La session ovviamente non è la risposta a queste due domande.
“La soluzione migliore è sempre la più semplice”. Io interpreto questa frase nel seguente modo, la soluzione per essere semplice deve esserlo sempre, semplice anche per chi la sfrutta e non solo per chi la realizza.
Senza andare tanto lontano e trovare soluzioni “poco semplici” la GoF come sempre ci viene incontro e ci fornisce una soluzione veramente semplice sia per chi la realizza che per chi la utilizza attraverso il Pattern Singleton.

Così come si può leggere su numerosi libri e su Internet, il pattern Singleton può essere implementato in diversi modi e appassiona molti studiosi . In particolar modo mi ha colpito la soluzione del Prof. Bill Pugh il quale fornisce una soluzione… semplice
come serve a noi.
public class Singleton {
private static Singleton singleton = null;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null) singleton = new Singleton();
return singleton;
}
}
o ancora meglio (il final ci dà la certezza)
private Singleton() {}
/**
* SingletonHolder è caricato alla prima esecuzione di Singleton.getInstance()
* o al primo accesso al SingletonHolder.instance , not before.
*/
private static class SingletonHolder {
private final static Singletoninstance = new Singleton();
}
public static SingletongetInstance() {
return SingletonHolder.instance;
}
Essendo privato, il costruttore può essere istanziato solo all’interno della classe, infatti come si vede, è il metodo interno getInstance() che controlla che la classe Singleton sia già stata istanziata almeno una volta. Se non è stata istanziata (singleton == null) provvede a farlo, altrimenti semplicemente ritorna la classe che è stata evidentemente istanziata prima. Da notare l’importanza del metodo statico, il quale nel momento in cui viene caricata la classe, in automatico viene memorizzata.
Questo è bellissimo e fa proprio al nostro caso, una classe intelligente che indistintamente dal fatto che noi sappiamo o no se è già stata istanziata se ne occupa lei di creare l’istanza e mantenerla in cache nella Virtual Machine restituendocela quando la richiamiamo. Ora che abbiamo creato la classe di base, al suo interno possiamo metterci tutte le variabili di cui abbiamo bisogno. Nel nostro caso abbiamo bisogno di memorizzare le classi di Business. Anche una semplice HashMap può fare al caso nostro, una mappa in cui inseriremo però solo le classi Business. La chiave sarà data dal nome della classe e il valore sarà la classe stessa.
public class Singleton {
private static Singleton singleton = null;
private HashMap businessClasses = new HashMap();
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null) singleton = new Singleton();
return singleton;
}
public HashMap getBusinessClasses() {
return businessClasses;
}
public void setBusinessClasses(HashMap businessClasses) {
this.businessClasses = businessClasses;
}
}
E’ inutile dire che ovviamente sfrutteremo i getters e i setters per impostare e richiamare le classi nella nostra cache.
Il vecchio codice per istanziare una classe di business era il seguente
public class BusinessExample {
public static BusinessInterface getBusinessInterface(String businessClassName) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class c = Class.forName(businessClassName);
BusinessInterface bus = (BusinessInterface)c.cast(c.newInstance());
businessClasses.put(businessClassName, bus);
return bus;
}
}
Come si vede, ad ogni richiamo, la classe verrà istanziata attraverso la Reflection, che sia stata già istanziata da un’altra chiamata o no.
Sfruttando invece la classe Sigleton appena realizzata possiamo ovviare a questo problema come segue
public class BusinessExample {
public static BusinessInterface getBusinessInterface(String businessClassName) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
BusinessInterface bus;
Singleton singleton = Singleton.getInstance();
HashMap businessClasses = singleton.getBusinessClasses();
if(businessClasses.containsKey(businessClassName)){
bus = (BusinessInterface)businessClasses.get(businessClassName);
System.out.println(“business già presente nella WM”);
}else{
Class c = Class.forName(businessClassName);
bus = (BusinessInterface)c.cast(c.newInstance());
businessClasses.put(businessClassName, bus);
System.out.println(“classe istanziata con la reflection”);
}
return bus;
}
}
La riga
Singleton singleton = Singleton.getInstance();
ci ritorna semplicemente l’unica classe Singleton istanziata, non effettua una nuova istanza, quindi tutto ciò che è stato memorizzato al suo interno precedentemente ce lo ritroveremo in qualsiasi momento,è per questo motivo che possiamo fare il controllo attraverso la IF, se la chiave è presente o meno nella HashMap businessClasses, e solo se la classe Business cercata non è stata istanziata si provvederà a farlo attraverso la Reflection
Abbiamo aggiunto solo le classi di Business nella classe Singleton, che come abbiamo visto ha assunto il ruolo di CacheManager, ma se se usata opportunamente è semplice sfruttare al meglio questa classe.
Supponiamo infatti di dover inserire in cache il nostro Logger preferito, basterà semplicemente aggiungerlo nella classe Singleton
public class Singleton {
private static Singleton singleton = null;
private static Logger logger = null;
private HashMap businessClasses = new HashMap();
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null) singleton = new Singleton();
return singleton;
}
public static Logger getLogger() {
return logger;
}
public static void setLogger(Logger logger) {
Singleton.logger = logger;
}
public HashMap getBusinessClasses() {
return businessClasses;
}
public void setBusinessClasses(HashMap businessClasses) {
this.businessClasses = businessClasses;
}
}
A differenza di quanto accade sfruttando la Session, con Singleton richiamare le variabili è semplicissimo, in quanto abbiamo i metodi elencati all’interno della classe stessa, senza impazzire a ricordarci il nome dell’attributo salvato nella Session.

Spero di essere stato all’altezza delle aspettative e spero che molti adottino questa soluzione quando si troveranno dinanzi ad un problema di cache management, se non vogliamo che la Gang of Four storca il naso
.


