venerdì 7 settembre 2012

Un pattern visto dal basso

Oggi descrivo l'Observer pattern.
Implementandolo si risolve in maniera elegante e senza particolare dispendio di energie il problema della gestione di eventi.
L'esempio che propongo è costituito da una serie di thread lanciati contemporaneamente: tramite questo pattern si controlla il loro stato per permettere di eseguirne un numero massimo predefinito alla volta (nel mio caso 15). I restanti rimangono in attesa che un thread completi la sua esecuzione. Chiaramente, questo pattern può essere usato in molti altri contesti, come per la gestione di una chat o per un'interfaccia grafica.

Ho creato una classe (ThreadService.java) che implementa l'interfaccia Observer (si cura di monitorare un evento che potrebbe essere generato) e un'altra interna (ThreadClass) ad essa che estende la classe astratta Observable (la classe avente l'evento "sotto controllo"). 
La classe interna è in realtà thread che, come si dirà più avanti, ha lo scope private.

Caratteristiche di ThreadService:
- singleton (tra l'altro, ha un costrutto privato!)
- implementa l'interfaccia Observer e il metodo astratto update
- contiene la classe privata ThreadClass
- il metodo addThread fa la new del thread e lo mette in una coda 
- il metodo execute controlla il numero di thread in esecuzione e li esegue se ci sono "posti disponibili"

Caratteristiche di ThreadClass:
- scope private per essere richiamato solo da addThread
- costrutto con un parametro per il nome del thread
- run è il body del thread

Ho tralasciato i metodi di Observer e Observable per vederli ora in dettaglio.
Alla fine del corpo del thread ho messo questi 3 metodi:
- addObserver: passa un oggetto Observer per "comunicare" che la classe in cui è chiamato questo metodo  addObserver deve cambiare lo stato (deve essere rimosso dalla lista dei thread)
- setChanged: segnala il cambiamento di stato
- notifyObserversnotifica agli osservatori (nel nostro caso a ThreadService), gli passa un  parametro (opzionale) e invoca il metodo update (di ThreadService nel nostro caso)

Invece l'implementazione di Observer  ha update come metodo chiave:
Banalmente, quando il thread completa la sua esecuzione richiama il metodo update di ThreadService il quale si occupa di togliere dalla coda il thread che ha appena finito la sua esecuzione e richiama l'execute così da verificare se ci sono thread in attesa. Bada bene che è assolutamente sbagliato pensare che il thread richiami direttamente il metodo update. Questo post ha un intento più pratico e meno teorico quindi spiego qua il funzionamento a basso livello. 

Infine, la firma di update ha due parametri, uno Observable e l'altro Object. Il primo indica la classe osservata in cui si è verificato il cambiamento di stato, il secondo serve per passare un valore qualsiasi (per es. al clic di un button passo da lì il suo valore...).
Ecco così spiegato il funzionamento del pattern: dall'Observable si segnala il cambiamento di stato, l'Observer registra tale evento.

Chiunque volesse testarlo può farlo "gratis" con tre passi:
1. crea un nuovo progetto Java
2. all'interno del Main inserisce il seguente codice:
ThreadService thread = ThreadService.getInstance();
for(int i =1; i<51; i++){
thread.addThread(i+"");
}
3. lancia il Main
Verranno chiamati in successione 50 thread.

Alla prossima,
Francès

Nessun commento:

Posta un commento