"Il
programmatore vero deve essere pigro
pigro per scrivere codice
ma non per pensare di cosa scrive!"
Introduzione
Sono stanco di scrivere il nuovo-stesso codice per ogni programma
nuovo. Ormai siamo nell'epoca dei pattern e dei framework.
Nell'articolo si descrive un framework flessibile che ti può
salvare un paio di giorni quando decidi di cominciare a scrivere
il tuo nuovo capolavoro. Parliamo
dei programmi del mondo reale. A prima vista sembra che fanno
pure logica di business che è chiaro diversa per ogni
applicazione. Ma non è proprio così. Ad esempio,
parecchie devono lavorare con opzioni. Ancora più spaziose
quelle che devono scrivere qualcosa in log. Direi che la lista
non finisce qui. Ma ad ogni cosa il suo posto. Cominciamo
Application
è il entry point nuovo
Il framework ti dà la possibilità di dimenticare
il metodo main. Definisce due nuovi entry point: run e quello
ancora più veloce - rush. Guardiamo il codice del metodo
run lui spiega la differenza meglio delle parole.
public
void run() {
try {
rush();
} catch ( Throwable ex ) {
Log.log.warning( ex.toString() );
}
}
Come
vedi, cambia poco, ma usando rush puoi non scrivere il blocco
try-catch al più alto livello. Il metodo run è
più classico, definito dall'interfaccia java.lang.Runnable.
La
domanda eterna
Così, per creare l'applicazione, devi definire un figlio
della classe Application e ridefinirci uno dei due entry point.
Ma come il framework si crea l'oggetto della classe? Il framework
non può sapere come tu chiamerai la classe. Chi e come
si crea il primo oggetto?
Per
risolvere questo problema il framework usa la linea di comando.
Aspetta come primo parametro il nome del figlio di Application.
Per la tua comodità c'è script file: si chiama
jboot e dà la possibilità di lanciare i tuoi
applicativi quasi come le altre applicazioni Java, la differenza
è solo che devi chiamare jboot invece di JVM. Cioè
scrivere qualcosa del genere:
jboot
-cp demo.jar it.company.app.Demo
Così
JBoot riceve il nome del figlio e crea la sua istanza usando
i metodi della classe java.lang.Class forName e newInstance.
Figura 1 - Un esempio della configurazione dell'applicazione
che usa JBoot
Factory
Subito dopo la creazione dell'oggetto di Applicazione si chiama
il metodo createFactory che implementa il pattern Factory
Method [1]. Il metodo crea l'oggetto Factory che implementa
un altro pattern - Abstract Factory [1].
L'uso
dei pattern dà la possibilità di costruire un'architettura
molto flessibile e facile per fare il reengineering, una cosa
importantissima riguarda che per il supporto si spende circa
un terzo del costo totale del sistema.
La
nostra Factory contiene la definizione dei metodi per produrre
le prossime classi:
- la
collezione delle opzioni;
- l'oggetto
di java.util.ResourceBundary;
- l'oggetto
di java.util.logging.Logger.
Molto
probabilmente per la tua applicazione servirà cambiare
logica di lavoro oppure produrre altri tipi di oggetti. In
questo caso puoi creare un figlio del classe Factory ed aggiungerci
i metodi necessari.
Via
L'ultima cosa che fa il metodo main è chiamare il metodo
start dell'applicazione. Cosa c'è dentro? Guardiamo
UML.
Figura 2 - Il diagramma statico delle classi.
Come
vedi, da parte delle classi Application e Factory, il framework
lavora anche con altre. Vediamo quando.
Figura 3 - Il ciclo di vita dell'applicazione
All'interno
del metodo Application.start si fa una serie di chiamate dei
Template Method [1]: init, run, destroy. Il metodo init crea
gli oggetti delle classi Options, ResourceBundle e Logger
chiamando gli appropriati metodi di Factory.
Opzioni
Parecchie applicazioni hanno delle opzioni. Il framework fa
l'accesso alle opzioni sincrono, fa il controllo dei tipi
e salva automaticamente le opzioni fino al prossimo lancio
dell'applicazione.
Per definire un'opzione nuova basta scrivere qualcosa del
genere:
public
final static Option < Date > LAST_UPDATE = new Option
< Date > ( "LAST_UPDATE", null );
public
final static Option < Boolean > CHECK_UPDATES = new
Option < Boolean > ( "CHECK_UPDATES", true
);
Usarla
è ancora più semplice, grazie a generics [2]
e autoboxing/unboxing [3].
if
( CHECK_UPDATES.get() ) {
final Date lastUpdate = LAST_UPDATE.get();
// ...
LAST_UPDATE.set( new Date() );
}
La
classe Option opera come Facade [1] e il suo compito principale
è fare il controllo di tipo usando generics. L'oggetto
della classe non contiene il valore dell'opzione ma solo il
suo nome che deve essere unico. Gestisce il valore nella classe
Options che può essere pensata come una Map sincronizzata
tra nomi e valori. Prima di chiudersi, l'applicazione, nel
suo metodo destroy, salva l'oggetto Options in un file usando
Serialization [4]. Al prossimo lancio, il metodo init dell'applicazione
recupera l'oggetto Options dal file. Così il valore
di default passato al costruttore d'oggetto Option si usa
solo al primo lancio dell'applicazione. Poi il valore si recupera
dal file che si trova nella home directory dell'utente.
Figura 4 - La classe Option opera come Facade.
Internazionalizzazione
E' ovvia l'importanza di seguire le regole d'internazionalizzazione
fin dalla fase iniziale dello sviluppo dell'applicazione che
potrebbe essere fruita in diverse lingue. Ma se l'applicazione
supporta una lingua sola, come la maggior parte, puoi anche
avere vantaggi seguendo le regole d'internazionalizzazione.
Il tuo codice si rende più pulito delle stringhe cablate
e diventa possibile riusarle, sia nella stessa applicazione
che in altre.
Le risorse testuali si usano intensamente perciò anche
la più piccola comodità aggiuntiva fa in modo
che il processo di scrivere il codice sia più facile.
Usando pure Java API per ritirare una riga testuale dal ResourceBundle
dobbiamo scrivere qualcosa di questo tipo:
String
text = resouceBundle.getString( "text" );
Il
framework definisce una classe-involucro che fa lo stesso
scrivendo:
String
text = Res.get( "text" );
Questa
soluzione è un po' più breve ma non è
perfetta neanche. Sviluppando il framework ho seguito lo scopo
di farlo più leggero possibile. Ma se ti interessa
migliorare ulteriormente la situazione leggi il mio articolo
"Come rendere l'uso delle risorsi testuali in Java facile
e sicuro" [6].
Log
Una cosa che è presente nella maggior parte delle applicazioni.
Facendo il framework più piccolo possibile ho scelto
java.util.logging.Logger introdotto in JDK 1.4. Per aggiungere
un messaggio d'informazione nel log basta scrivere:
Log.log.info(
"L'avvio in corso..." );
Ma
se devi fare più chiamate c'è senso ad usare
static import [5] introdotto in JDK 5.0.
import
static it.esistema.jboot.Log.log;
//...
log.info(
"L'avvio in corso..." );
log.info( "Il carico di dati..." );
Ciao
mondo!
Con il framework va la classica applicazione "HelloWorld".
Il suo codice è tutto qui:
import
it.esistema.jboot.*;
public
class Demo extends Application {
protected void rush() throws Exception {
Log.log.info( Res.get( "txt.hello_world"
) );
}
}
Come
vedi è rimasto abbastanza corto! Ma ora puoi subito
salutare il mondo in italiano.
Conclusione
Java API ti dà la massima flessibilità per l'implementare
il processo di bootstrap. Il punto è che devi implementare
il processo per ogni applicativo nuovo quando cominci a scrivere
il codice
e sentire guardandolo "Déjà
vu". JBoot ti dà la possibilità di cominciare
subito a scrivere la logica di business, creando per te gli
oggetti delle classi più comuni: Factory, Options,
ResourceBundle, Logger. Puoi sempre adattare il processo alla
sua necessità grazie all'architettura flessibile basata
sui pattern riconosciuti. Prova e regalati un po' di tempo
per bere il caffè!
Sorgenti
Il progetto JBoot si distribuisce come un progetto con sorgenti
aperte (open source). Puoi scaricarlo gratuitamente dall'indirizzo
http://esistema.it/pubblicazioni/jboot/jboot-src.zip .
Bibliografia
[1] Stephen Stelting; Olav Maassen - Applied Java Patterns,
Prentice Hall PTR, 2002, ISBN 0130935387
[2] Sun Microsystems, Inc. - Generics, Java JDK 5.0 Guide,
2004
[3] Sun Microsystems, Inc. - Autoboxing/Unboxing, Java JDK
5.0 Guide, 2004
[4] Sun Microsystems, Inc. - Object Serialization, Java JDK
5.0 Guide, 2004
[5] Sun Microsystems, Inc. - Static Import, Java JDK 5.0 Guide,
2004
[6] Yury Fedorov - Come rendere l'uso delle risorsi testuali
in Java facile e sicuro, MokaByte, settembre 2004
Yury
Fedorov laureato in Tecnologie Informatiche, lavora da
più di 6 anni nel settore IT. Dal 1999 si occupa di
Java ed in particolare dello sviluppo di applicazioni web
J2EE. Dopo diverse esperienze di disegno e sviluppo ora si
occupa in particolare di aspetti architetturali per progetti
rivolti al mercato e-business. Ha numerosi certificati di
Brainbench e in particolare Master Java, Internet Professional
Web Developer Client-side e Internet Professional Web Developer
Server-side.
|