Skip to main content

Full text of "Io programmo 121"

See other formats


ANTEPRIMA MS EHITITY SERVER 

IL FRAMEWORK TUTTO IN UNO CHE FACILITA LA GESTIONE 
DEI DATI IN OGNI PROCESSO DI SVILUPPO 



□ 



VERSIONE STANDARD 



RIVISTA+UBRO+CD €9,90 



f^ l RIVISTA+CD €6ft0 



ROGRAMMO 



PER ESPERTI E PRINCIPIANTI 



dal PC al 
telefonino 



Sviluppa l'applicazione che ti consente 
di inviare un messaggio a più destinatari 
usando un comodo software lato desktop 

•per il computer prepara un'interfaccia 
che ti permette di selezionare i destinatari 
e scrivere il testo 

•per il cellulare crea un server 
che riceve il messaggio e l'elenco 
di destinazione dal PC tramite bluetooth o usb 

•tecnica usa le Remote API per controllare 
lo Smartphone e inviare gli SMS con un solo 
click del mouse 



INTERNET EXPLORER 



Ti spieghiamo come usare Javaampi e pu«.u aiuu pei «icnucic 
le funzionalità del browser di casa Microsoft 




III 



HACKING DI GMAIL 

Accedi a Google Mail direttamente 
da PHP. Ecco la libreria per utilizzare 
lo spazio in modo "fantasioso" 



TAG CLOUD IN .NET 

Crea un controllo che mostra 
gli argomenti più letti in un sito 
sfruttando la dimensione dei font 



CREA "IL" MESSENGER 

Impariamo come funziona 
il networking in Java con 
un esempio divertente! 



MIGLIORA IL TUO STILE 

Scopri il Refactoring. Rinomina 
oggetti e classi senza dover 
modificare manualmente il codice 



FATTI AIUTARE 
DA JMATTER 

Ecco il framework che crea 
un'applicazione completa, 
e dettagliata in pochissimi secondi 



PROGRAMMI PERFETTI 
CON LA OOP 

Sotto la lente tre pattern per 
imparare a sfruttare tutta la potenza 
della programmazione ad oggetti 



MULTIMEDIA 



LA VALIDAZIONE 
DEI DATI IN FLEX 

Ottieni form in "formato Flash" 
a prova di input utilizzando il 
framework di Macromedia 



PATTERN 



EVITIAMO GLI ERRORI 
DI ALIASING 

La guida passo passo per 
implementare correttamente 
il Pattern Value Object 



#> 



ISOLUZIOIMI 



CONFRONTO FRA TESTI: SCOPRIRE LE DIFFERENZE FRA DUE O PIÙ 
CONTENUTI NON È UN'OPERAZIONE BANALE. ECCO COME OTTIMIZZARLA! 



sin 



EDIZIONI 

MASTER 9 " 7" V 28 59 4 009 

www.edmaster.it 




31-10-2007 16:51:01 



004-005 editoriale: 004-005 editoriale 2-11-2007 12:09 Pagi 





Questo mese su ioProgrammo 



VOTO DIECI 



Ruby e Python. Se ne parla ormai da anni come 
due nuovi linguaggi emergenti. Ed è già para- 
dossale che due linguaggi che esistono da moltissimi 
anni vengano etichettati come nuovi, ed è al- 
trettanto paradossale che vengano etichettati co- 
me emergenti. E' ora di sdoganare questi due lin- 
guaggi come: "maturi" ed "efficaci". 
C'è in Italia una sorta di diffidenza rispetto a ciò 
che appare come non convenzionale, per cui sia 
Ruby che Python nel nostro paese tendono a la- 
vorare dietro le quinte senza mai riflettere quel- 
l'interesse che nel resto del mondo e special- 
mente in America è invece una realtà acquisita. 
Tuttavia sia Ruby che Python sono due linguag- 
gi decisamente utili e interessanti. Primo per- 
ché hanno una curva di apprendimento vicina 
allo zero, secondo perché sono dotati di costrut- 
ti che li rendono particolarmente orientati alla 



produttività individuale e aziendale. Una parola 
in più voglio spenderla su Ruby On Rails, il fra- 
mework per lo sviluppo Web che tanto ha susci- 
tato clamore nel mondo e che invece qui in Ita- 
lia è ancora utilizzato da una cerchia ristretta. Si 
tratta di un framework assolutamente "meravi- 
glioso". Si riescono a creare complete applica- 
zioni Web in qualcosa come due ore. E non stia- 
mo parlando di un sitino personale, ma di ap- 
plicazioni complesse aderenti al pattern MVC e 
con funzionalità avanzate. Provare per credere! 
Da queste pagine vogliamo esortarvi a provare a 
programmare in Python o in Ruby non perché il 
linguaggio che state utilizzando adesso sia meno 
efficace, ma perché siamo convinti che per una 
quantità sterminata di applicazioni questi due 
linguaggi possano rendervi l'attività di pro- 
grammazione molto più semplice e divertente. 




UcdU web 

nome_file.zip 



All'inizio di ogni articolo, troverete un simbolo 
che indicherà la presenza di codice e/o software 
allegato, che saranno presenti sia sul CD (nella 
posizione di sempre \soft\codice\ e \soft\tools\) 
sia sul Web, all'indirizzo 
http://cdrom.ioprogrammo.it. 




dal PC al 
telefonino 

friluqifH rappikHiQne cheti consente 

di inviare un messaggio a più destinatari 
usando un comoda software latodeskttp 

^(■n L UWW'UIW prqwai urrintaficba 
che U permette A selezionare i destinatali 
v ìorvEfF il tata 

4/Pet L CELLULARE cita un HT-r 

die riceve il nwssaffl» e l'elevo- 

di deturvaiiff* dai PC Tràmite MutUel» o usb 

^tkmu usa te Remote API per controllale 
fc> SrrurlPtarK- e intuir* gì SMS con un solo 
Ci* (W mqwt 



004-005 editoriale: 004-005 editoriale 2-11-2007 12:09 Pagi 



Questo mese su ioProgrammo 



INTERNET EXPLORER ADDOM 

Ti spieghiamo come usare Javascript e poco altro per estendere 
le funzionalità del browser di casa Microsoft 



-0- 



IOPROGRAMMO WEB 



PHP incontra Google mail 
pag. 20 

Hai mai pensato di usare gmail come 
archivio FTP? ti piacerebbe accedere alla 
posta direttamente da una tua Web 
Application PHP? Ti presentiamo la libre- 
ria che ti consente di fare tutto ciò. Poche 
righe di codice e gmail non avrà più seg- 
reti! 

PHP ad oggetti tecniche avanzate 
pag. 28 

/ Design Patter rappresentano i pilastri 
fondamentali di un progetto destinato al 
successo. Essi costituiscono il cuore pul- 
sante della programmazione orientata 
agli oggetti. Vediamo come implementar- 
ne alcuni in PHP 5 

Nuvole all'orizzonte 
pag. 35 

// Web 2.0 ha introdotto il concetto di 
"Tag Cloud". In ogni blog o sito che si 
rispetti esiste una rappresentazione grafi- 
ca degli argomenti che vede le discussioni 
più in voga visualizzate con un font più 
grande. Vediamo come fare in .Net 



SISTEMA 



Creare Addon per Internet 
Explorer 
pag. 42 

Molti pensano che lo sviluppo di Add-on 
per IE sia riservato a programmatori C++, 
vediamo come è invece possibile aggiun- 
gere nuove funzionalità al Browser sem- 
plicemente attraverso dei semplici script 

Jmatter semplifica lo sviluppo in 
Java 
pag. 46 

Le applicazioni software spesso compren- 
dono un set di funzionalità molto simili; 
perchè implementarle ogni volta da zero? 
Oggi tutto ciò si può evitare e Jmatter ti 
da una mano a fare tutto più velocemen- 
te 



NETWORKING 



Realizzare un Instant Messenger 
pag. 54 

Lo sviluppo di un instant messenger può 
essere un'attività molto interessante che 
ci permetterà di addentrarci nei meandri 
del networking e di realizzare un'appli- 



cazione di immediato utilizzo pratico 



SISTEMA 



Riprogrammare il codice 
con stile 
pag. 60 

Hai scritto il tuo fantastico software. Ora 
ti accorgi che avresti potuto usare nomi 
più significativi. Come migliorare il tuo 
software senza dover cambiare manual- 
mente tutti i riferimenti? A questo è a 
molto altro ci pensa il re factoring! 



DATABASE 



Microsoft entity framework 
pag. 68 

La maggior parte delle applicazioni fa 
uso di dati e la loro gestione è sempre 
stato uno dei problemi fondamentali 
della programmazione software. 
Vediamo come tutto ci viene reso più 
semplice attraverso l'utilizzo del frame- 
work 



SISTEMA 



Validare l'imput usando Flex 
pag. 80 

Affrontiamo uno dei problemi basilari 
per ogni programmatore: controllare la 
corretta immissione dei dati. Come esem- 
pio applicativo utilizzeremo una Form 



RUBRICHE 



Gli allegati di ioProgrammo 

pag. 8 
// software in allegato alla rivista 

Il libro di ioProgrammo 

pag. 6 

// contenuto del libro in allegato 
alla rivista 

News pag. 10 

Le più importanti novità del 
mondo della programmazione 

Tips & Tricks pag. 76 

Una raccolta di trucchi da tenere a 
portata di... mouse 

Software pag. 110 

/ contenuti del CD allegato ad 
ioProgrammo. 



pag. 24 

Flash per l'autenticazione degli utenti 

Dieci cose da non fare in C++ 
pag. 86 

Chi inizia col C++ è sempre portato a fare 
gli stessi errori. Questi a volte producono 
programmi ma/funzionanti, bug critici, o 
semplicemente lo schermo da parte dei 
più esperti, ecco come evitarli 



MOBILE 



Il ritorno di Packman per pocket 
pag. 94 

Sicuramente la maggior parte di voi 
ricordano Packman: il pupazzo sferico 
che deve mangiare quante più pillole 
possibili senza farsi catturare dai fantas- 
mi di turno. In questo articolo ne pro- 
grammeremo uno per cellulare 



SISTEMA 



Il pattern Value Object 
pag. 102 

Gli errori di "Aliasing" sono tra le cause 
più comuni di bug insidiosi nella pro- 
grammazione a oggetti. Un pattern sem- 
plice ma importante di nome value 
object ci aiuta ad eliminarli definitiva- 
mente 



SOLUZIONI 



Correlazione tra testi 
pag. 111 

Nell'ambito della linguistica matematica 
è particolarmente interessante il proble- 
ma del confronto tra testi e della conse- 
guente valutazione di elementi comuni. 
Vediamo come affrontarlo informatica- 
mente 



QUALCHE CONSIGLIO UTILE 

I nostri articoli si sforzano di 
essere comprensibili a tutti coloro 
che ci seguono. Nel caso in cui 
abbiate difficoltà nel comprendere 
esattamente il senso di una 
spiegazione tecnica, è utile aprire 
il codice allegato all'articolo e 
seguire passo passo quanto viene 
spiegato tenendo d'occhio l'intero 
progetto. 



G 



http://forum.ioprogrammo.it 



006 Presentaz Libro: 008 31-10-2007 17:12 Pagina 6 



Le versioni di ioProgrammo 




■€+ 




fflRpfìRAMMO RIVISTA + LIBRO 

+ CD-ROM 

in edicola 




SOL SERVE* 

ASPETTI AVANZATI 



■*0:W~ 




I contenuti del libro 



SQL SERVER ASPETTI AVANZATI 



v 



Microsoft SQL Server per molti versi non è 
solo un database. Lo si può considerare 
come un ambiente completo che espone al 
programmatore funzionalità complesse che 
abbracciano a 360 gradi la gestione dei dati. 
Come si possono creare programmi in T-SQL? 
Quali sono le modalità con cui SQL server 
interagisce con il .NET framework? Come posso 
ottimizzare al massimo le query verso il 
database? e ancora quali sono gli strumenti di 
programmazione diretta che SQL server ci mette 
a disposizione? A queste e a tante altre domande 
risponde questo Handbook. Essenziale quanto 
diretto, Vito Yessia ci mostra una serie di esempi 
concreti su come utilizzare al meglio tutte le 
tecniche più avanzate legate al gigantesco 
database server di casa Microsoft 



DA T-SQL ALL'INTEGRAZIONE CON 
IL FRAMEWORK.NET. ECCO COME 
SFRUTTARE AL MASSIMO IL 
DATABASE DI MICROSOFT 

• Programmazione con T-SQL 

• Integrazione con il framework .NET 

• Catalogo e funzioni di sistema 



* 6/Dicembre 2007 



http://www.ioprogrammo.it 



008 Presentaz CDRom 1:010 31-10-2007 17:18 Pagina 8 



Le versioni di ioProgrammo 




telefonino 




RIVISTA + CD-ROM 

in edicola 



SPICES.NET 
SUITE 5.2.0.8 

4 programmi in uno 

La suite raccoglie un obfusca- 
tor, un decompiler, un modeler 
e un investigator.L'obfuscator 
consente di "criptare" il bina- 
rio di un codice .NET di modo 
che non sia facilmente possibi- 
le disassemblarlo ed ottenerne 
il codice originale. Il decompi- 
ler viceversa consente di 
decompilare un software .NET 
e visionarne la struttura. A - 

completare la suite due stru- 
menti utilissimi, il primo: il 
modeler consente di progettare il proprio applicativo 
ed il secondo di navigarne i metadati. Si tratta una 
suite veramente ben studiata che fornisce al pro- 
grammatore una base certa quando si vogliono inte- 
grare o modificare programmi scritti da altri. 



-0- 



Come usare l'interfaccia del CDRom 



IL SOFTWARE 



Una accurata recensione 
dei contenuti 



■EEBB1- 

Il top software del mese 
individuato dalla redazione 



IL SOFTWARE 



Il software diviso 

in categorie per 

una comoda consultazione 



Torna alla pagina iniziale 
del CD-ROM 



CONTATTACI 



*-EiEna 



-BEHÌM1 

L'elenco del software 
contenuto nelle categorie 



DIMENSIONE 



La dimensione 
del software sul CD 




RICERCA SOFTWARE 



Clicca qui per installare o 
salvare il software sul tuo PC 



Abbonamenti informazioni 
e servizi utili 



Vuoi inviare una email alla 
redazione con le tue richieste 



I siti più interessanti II database di tutti i software 

del mese selezionate pubblicati da ioProgrammo 
per te anche gli arretrati 



* 8/Dicembre 2007 



http://www.ioprogrammo.it 



010-011:014-015 2-11-2007 11:47 Pagina 10 



NEWS T 



DONNE NELL'IT CHE FATICA! 



■e- 



CE UN PO 1 DI 
GOOGLE IN MYSQL 

~ he a Google piacesse MySQL era ar- 
cinoto. Tanfè che spesso e volentie- 
ri sono state rilasciate patch prodotte 
dal gigante dei motori di ricerca tese a 
migliorare le caratteristiche di MySQL. 
Tuttavia, lentamente, la collaborazione 
fra MySQL AB e Google sta uscendo dai 
backstage per assumere una rilevanza 
più istituzionale. Particolare interesse ri- 
vestono le parole di David Axmark vice- 
presidente di MySQL AB che ha sottoli- 
neato come ormai esistano tutte le basi 
legali per includere ufficialmente le pat- 
ch prodotte da Google nelle release uf- 
ficiali di MySQL. Le prime contribuzioni 
dovrebbero apparire nella versione 6.1 del 
DB server prevista per il 2009 e dovreb- 
bero direzionarsi verso una migliore ge- 
stione delle repliche e del numero di 
istanze del database 

F# ESCE DAL 
LABORATORIO 

~"^\a tempo si parla ormai di F#, il nuo- 
vo linguaggio di Microsoft che do- 
vrebbe riunire un misto dei migliori lin- 
guaggi di scripting in circolazione con le 
tecniche ormai consolidate offerte da 
.NET. Fino a ieri F# è stato prima di tutto 
un progetto di studio prima che un og- 
getto concreto, oggi arriva l'annuncio 
della formazione di un team apposito 
che porti avanti lo sviluppo di F#. L'idea 
è di dare consistenza al linguaggio in 
tempi abbastanza rapidi. F# nasce per 
supportare campi dello sviluppo relati- 
vi alla matematica finanziaria e scienti- 
fica, per intenderci quelli che sono at- 
tualmente coperti da strumenti come 
Matlab 

PICCOLI GRANDI 
BACHI PER LA JRE 

Sun avvisa che è necessario aggiorna- 
re il proprio Java Runtime Environ- 
ment all'ultima versione disponibile. E' sta- 
ta infatti appena trovata una falla che 
potrebbe consentire ad un applet mali- 
gna di guadagnare privilegi che potreb- 
bero consentirgli di danneggiare il si- 
stema. Tutte le versioni fino alla JRE 6 
Update 2 potrebbero essere affette dal 
bug, quindi è importantissimo aggior- 
nare all'update 3. 




Un carattere indomito, uno stoicismo pro- 
fessionale, un senso intrepido dei lega- 
mi all'azienda e una certa dose di self-pro- 
motion, sia personale che sul lavoro: queste 
sono le prerogative di una ventina di donne 
che il 19-21 ottobre si sono riunite a casa di Deir- 
drè Straugham, sul lago di Como. Non tutte 
insieme, no, ma un po' alla volta, secondo 
quello che ognuno aveva da fare e quando 
volevano, perchè tutte hanno una famiglia 
di cui prendersi cura, dei fidanzati che le 
aspettano, dei figli da mettere a letto la sera. 
Ma queste donne non solo solo casalinghe, mo- 
gli, madri, fidanzate o figlie ma sono inge- 
gneri programmatrici, senior analyst, pro- 
grammatrici e disegnatoci web, blogger pro- 
fessionale e organizzatrici di eventi, sysad- 
min, manager per il supporto tecnico per 
grandi e medie aziende, proprietarie di pic- 
cole ditte di consulenza informatica. Deir- 
drè, che ha ideato l'incontro, è senior web 
producer per la Sun e lavora come analista 
di contenuti per altre aziende, cioè dice loro 
se il messaggio che vogliono comunicare at- 
traverso il loro sito o il loro blog viene recepito 
correttamente dai visitatori e possibili com- 
pratori. Abbiamo chiesto proprio a Deirdrè 
perchè ha invitato a casa sua tante donne 
professioniste dell'IT e cosa vuole ottenere. 
"Siamo sempre pie frustrate per la pochissi- 
ma visibilità che hanno le donne nella tec- 
nologia in Italia. Così sin da giugno qualcu- 
na di noi ha pensato di riunirsi e ha elabora- 
to un piano per cominciare a fare qualcosa 
al riguardo. Gli uomini a volte fanno una self- 
promotion spietata e si conoscono fra loro, 
si aiutano o, perlomeno, si informano l'un 
l'altro, a meno che non lottino per lo stesso po- 



Enrica Garzilli - http:IOrientalia4All.net 
sto. Il primo passo per noi era quindi stare 
insieme per conoscersi e scambiare le espe- 
rienze e per sapere esattamente cosa fare, 
elaborare una strategia comune. Ancora non 
lo sappiamo di preciso ma siamo tante in Ita- 
lia. Poi, ovviamente, vogliamo costituire una 
lobby di donne professioniste nell'IT. In quan- 
to tali siamo svantaggiate sia come donne 
che come lavoratrici, l'unica legge che, in teo- 
ria, ci tutela pienamente è il congedo per la ma- 
ternità, che in Italia è molto lungo e davvero 
garantito. Però è del tutto legale in Italia che 
un possibile datore di lavoro di chieda l'età e 

10 stato civile e, se sei in età fertile, ottenere un 
lavoro a livello delle tue qualifiche o cam- 
biare lavoro per fare carriera è difficilissimo, 
le aziende preferiscono sempre assumere o 
premiare un uomo che, secondo loro, è più pre- 
sente e che < questa è la loro scusa > si con- 
centra sul lavoro invece che sui figli." Da que- 
sta serie di incontri sono venute fuori delle 
proposte e un piano di azione interessante. Per 
prima cosa è stato aperto un gruppo di di- 
scussione su Yahoo, uno su Linkedin e un 
blog. Lo scopo? I gruppi di discussione sono 
essenzialmente per scambiarsi idee di lavo- 
ro, informazioni sui posti vacanti e le offerte 
di lavoro e sulle retribuzioni. Il blog è princi- 
palmente la loro "faccia pubblica" dove scam- 
biare idee e progetti col resto del mondo in par- 
te per aiutare altre donne e in parte per fare 
pubblicità e dare visibilità a loro stesse e al- 
le loro abilità lavorative. Era stato aperto an- 
che un gruppo dedicato su Facebook ma sem- 
bra non aver avuto molto successo ed è sta- 
to abbandonato. Il social network è molto 
usato dalle donne e viene usato quindi non 
solo per mettersi in comunicazione e per co- 
noscersi, ma per scambiarsi informazioni 
utili per il lavoro o la carriera. Fra i progetti 
futuri c'è l'organizzazione di Girl Geek Din- 
ner e una conferenza internazionale dove a 
parlare sono solo le donne. Molto importante 
è stata la discussione sulle qualifiche e le re- 
tribuzioni. Tutte le donne, nessuna esclusa, 
hanno detto che non solo le aziende nell'IT 
preferiscono assumere gli uomini, specie se 
sono programmatori, ma a parità di qualifi- 
che, di capacità, di anzianità di lavoro e di 
ore dedicate all'azienda, gli uomini nell'IT 
sono pagati dal 10 al 20% in più delle donne. 

11 perchè non è chiaro, molte hanno prote- 
stato e spesso hanno avuto un avanzamen- 
to di ruolo o di retribuzione ma solo dopo 
aver minacciato il licenziamento. 



y IO /Dicembre 2007 



http://www.ioprogrammo.it 



010-011:014-015 2-11-2007 11:47 Pagina 11 



NEWS T 



UNA CONFERENZA "AGILE" 



Enrica Garzilli 



-e- 



Il 23 novembre a Bologna si terrà 
una conferenza davvero singola- 
re, l'Italian Agile Day. Perché singo- 
lare? Innanzi tutto perché è gratui- 
ta, poi perché è dedicata alle meto- 
dologie Agili per lo sviluppo e la ge- 
stione dei progetti software come 
Extreme Programming, SCRUM, Fea- 
ture Driven Development, DSDM, 
Crystal e Lean Software Develop- 
ment. I partecipanti alla conferen- 
za, che si tiene dal 2004, aderisco- 
no, se non concretamente almeno 
idealmente, all'Agile Manifesto. Que- 
sto è un manifesto per lo sviluppo del 
software "agile" che risponde al re- 
quisito di base: la priorità di chi vi 
aderisce è soddisfare il cliente con 
continui e veloci rilasci di software. 
I firmatari aderiscono a quattro prin- 
cipi fondamentali. Il primo è che gli 
individui e l'interazione fra essi pre- 
vale sui processi e sui mezzi è svi- 
luppare un programma quindi è un 
atto in cui la parte del leone la fan- 
no gli hacker coinvolti e le gli uten- 
ti e non è più object-oriented, fina- 
lizzato alla pura creazione e rilascio 



di codice, ma un processo collabo- 
rativo; il secondo principio è che 
software viene considerato un pro- 
cesso che si sviluppa man mano e 
che non richiede una documenta- 
zione iniziale completa; il terzo prin- 
cipio è si ricerca la collaborazione 
del cliente, piuttosto che la nego- 
ziazione contrattuale è il cliente 
quindi non è un nemico con cui fa- 
re dei patti il più vantaggiosi possi- 
bile per lo sviluppatore, 

ma è un consumatore le 
cui esigenze e i cui consi- 
gli aiutano, in pratica, a 
sviluppare in modo più ef- 
ficiente; l'ultimo principio 
è che il software deve ri- 
spondere ai cambiamenti, 
essere quindi flessibile, 
piuttosto che seguire un 
piano predeterminato. Da 
questo ne consegue che il 
rilascio del programma de- 
ve essere veloce, in modo 
da avere subito il feedback 
dal cliente, che permette 
a sua volta di modificarlo o . 



di indirizzarlo nel modo giusto. Un 
principio base è la semplicità, per- 
chè l'arte di massimizzare il lavoro non 
fatto è essenziale, è un po' quello 
che chiunque scriva professional- 
mente impara a sue spese: il meno 
è più. Sono aperte le iscrizioni a par- 
lare ed è stato attivato il conto Pay- 
Pal per le donazioni. Per maggiori 
informazioni info@agileday.it o 
http://www.agileday.it/index.php. 



p rodile 
«tnergi 
me1ho( 

- ÀI50 

llftES 



WEB: CHE SIA LA "VOLTA" BUONA? 



La mozione d'ordine è sempre la stessa: 
rendere lo sviluppo di applicazioni web 
immediato. Microsoft si arrovella con que- 
sto problema da tempo immemore pro- 
ponendoci sistematimaticamente nuove 
soluzioni, eleganti, tecnologiche, sempre più 
semplici, eppure non manca mai di pro- 
porne una nuova, sempre migliore della 
precedente. La nuova soluzione targata MS 
si chiama "Volta" ed è stata presentata re- 
centemente durante l'OOPSLA (Object- 
Oriented Programming, Languages, Sy- 
stems and Applications) a Montreal. Il re- 
sponsabile del progetto "ErikMeijer" così 
si è espresso parlando di Volta: Se pensate 
a quando i programmatori Visual Basic 
hanno fatto la loro comparsa sul mercato, 
vi renderete conto che a quei tempi non 
era facile scrivere applicazioni per Win- 
dows. Dovevate essere dei programmato- 
ri C++ e solo con l'arrivo di VB la gente è 



stata in grado di scrivere programmi per 
Windows. Adesso siamo negli anni del Web 
ma per certi versi siamo tornati indietro ai 
tempi della programmazione per Win- 
dows". 

L'idea di Meijer perciò è "democratizzare" 
lo sviluppo di applicazioni per la rete. No- 
nostante queste premesse Meijer si è lan- 
ciato in una serie di discussioni sulla pro- 
grammazione Multitier. Attualmente scri- 
vere un'applicazione per il Web significa 
lavorare su più Tier. Una parte verrà affi- 
data al client, ad esempio utilizzando Ja- 
vascript o i CSS un'altra verrà affidata ai ser- 
ver e così via. Esiste secondo Meijer una stra- 
tificazione troppo massiccia delle appli- 
cazioni, così il cardine che muove "Volta" 
sarà quello di consentire agli sviluppato- 
ri si scrivere software trasparente a questi 
strati e decidere solo in seguito al deploy 
come debba essere distribuita l'applicazione. 



Come Meijer voglia raggiungere lo scopo 
al momento lo ignoriamo. Certo che se le 
premesse per semplificare lo sviluppo di 
applicazioni Web sono queste, vedremo 
quali saranno le conclusioni. 




http://www.ioprogrammo.it 



Dicembre 2007/ 11 ^ 



012-018:032-035 30-10-2007 15:35 Pagina 12 



COVER STORY T ■ Inviare SMS dal computer 



MULTI SMS DAL PC 
AL TELEFONINO 

COLLEGHIAMO UN CELLULARE AL PC. SVILUPPIAMO UNA PICCOLA APPLICAZIONE DESKTOP 
CHE CONSENTE DI SCRIVERE MESSAGGI DA INVIARE A DESTINATARI MULTIPLI UTILIZZANDO 
ACTIVESYNC E LE REMOTE API DI WINDOWS MOBILE 



^ 




G CD CJ WEB 

SmartphoneSMS.zip 




SDK DI 

WINDOWS 

MOBILE 

L'SDK di Windows 

Mobile è scaricabile 

all'indirizzo 

http://msdn2.microsoft.co 

m/it-it/windowsmobile/ 

bb264327.aspx 



n 




REQUISITI 



Mi.muj.ujiu.um 

.NET Framework 



Visual Studio 2005, 
Windows Mobile SDK 



Tempo di realizzazione 



00000 



I cellulari si stanno progressivamente evolven- 
do fino a diventare veri e propri mini- compu- 
ter con funzioni di PIM (personal informa- 
tion manager) e interfacce utente elaborate. 
Gli Smartphone, in particolare, sono equipaggia- 
ti il sistema operativo Windows Mobile che non 
solo offre funzionalità evolute, ma consente a noi 
programmatori .NET di esplorare nuove poten- 
zialità di sviluppo. 

Il cugino "minore" di Windows supporta infatti 
una propria versione del .NET Framework e 
Visual Studio 2005 è perfettamente attrezzato per 
lo sviluppo di applicazioni per i dispositivi mobi- 
li. La nota dolente, per i fan di .NET, è che molte 
delle funzionalità esposte dalle API per Windows 
Mobile sono accessibili solo agli sviluppatori C++ 
"nativi". 

Tuttavia esistono modi per aggirare tali limita- 
zioni e continuare a sviluppare col nostro amato 
Framework applicazioni anche non banali. 
In particolare, in questo articolo vedremo come 
sviluppare un'applicazione che consente di 
inviare un SMS a più destinatari attraverso un PC 
collegato ad un telefonino Smartphone attraver- 
so una connessione ActiveSync. 



L'AMBIENTE 
DI SVILUPPO 

Prima di partire con il nostro programma è 
necessario compiere alcuni passaggi per confi- 
gurare correttamente l'ambiente di sviluppo. 
Innanzitutto occorre installare nella macchina 
l'SDK di Windows Mobile (la versione corrente 
dell' SDK è quella per Windows Mobile 6, ma 
molti dispositivi montano ancora Windows 
Mobile 5 quindi noi lavoreremo su quest'ultima). 
Con Visual Studio è possibile anche testare le 
proprie applicazioni direttamente sul telefonino, 
tuttavia, anche se possediamo uno Smartphone, 
è preferibile sviluppare e debuggare il program- 
ma su un emulatore. 



Per avviare un emulatore nel menu di Visual 
Studio andiamo alla voce Strumenti>Gestione 
emulatori dispositivo come in figura 1. 
Scegliamo quindi uno degli emulatori di 




Fig. 1: Gestione emulatori dispositivo 



Windows Mobile nella finestra di dialogo che si 
aprirà (fig. 2) , attiviamo il menu contestuale con 
il tasto destro e clicchiamo su connetti. 







Fig. 2: Scelta dell'emulatore dispositivo 



A questo punto si aprirà una finestra, come quel- 
la mostrata in figura 3, che mostra l'interfaccia di 
emulazione. 



► 12 /Dicembre 2007 



http://www.ioprogrammo.it 



012-018:032-035 30-10-2007 15:35 Pagina 13 



Inviare SMS dal computer ■ T COVER STORY 



-0- 



«* ■!*! 




Fig. 3: L'emulazione in funzione 



Nel nostro caso però questo non basta, noi 
dovremo infatti sviluppare un'applicazione che 
utilizza una connessione ActiveSync per comu- 
nicare tra il PC ed il dispositivo, quindi è necessa- 
rio anche emulare la connessione. 




Per far questo per prima cosa assicuriamoci di 
aver installato sulla macchina di sviluppo 
ActiveSync e che sia in esecuzione, dopodiché 
torniamo sulla finestra di dialogo che mostra i 
dispositivi di emulazione che abbiamo visto in 
figura 2 , attiviamo il menu contestuale sul dispo- 
sitivo connesso e scegliamo la voce Inserisci in 
alloggiamento come in figura 4. 
A questo punto ActiveSync dovrebbe avviare la 
procedura guidata di riconoscimento e connes- 
sione. 



IL PROGRAMMA 

Terminate queste operazioni preliminari di pre- 
parazione affrontiamo il programma vero e pro- 
prio. 

L'obiettivo è quello di sviluppare un'applicazio- 
ne Desktop che "chiama" un processo remoto 
(un programma insomma) che risiede sullo 
Smartphone passandogli delle informazioni che 
rappresentano l'sms da inviare; il programma 
remoto compie tutte le operazioni del caso e 
"comunica" all'applicazione sul PC l'esito. 



REMOTE API (RAPI) 

Primo grosso problema : in che modo controlla- 
re lo Smartphone da un programma Desktop? 
In effetti per gli sviluppatori C esiste una libreria 
che si chiama RAPI (Remote API) destinata pro- 
prio a questo scopo, anche in .NET si possono 
utilizzare le funzioni RAPI attraverso plnvoke, 
tuttavia rimappare una libreria di tali dimensioni 
non è propriamente un lavoro simpatico. 
Per fortuna il sito www.opennetcf.com mette a 
disposizione una libreria .NET , OpenNETCE- 
Desktop.Communication Library, che fa per noi 
tutto il duro lavoro di colloquio con RAPI. 
A corredo della libreria c'è anche un help e 
comunque si può consultare anche la documen- 
tazione di RAPI nell'help di Windows Mobile 
SDK, tuttavia vediamo in un breve esempio pra- 
tico lo schema di una chiamata di una funzione 
remota con RAPI che serve per ottenere informa- 
zioni sullo stato della batteria: 

Private Sub TestRapi() 
Dim rapi As New 

OpenNETCF. Desktop. Communication. RAPI 
If rapi.DevicePresent Then 
rapi.Connect(True, 10) 



Dim pw As New 




SYSTEM_POWER_STATUS_EX 



Fig. 4: avvio della connessione ActiveSync 



rapi.GetDeviceSystemPowerStatus(pw) 
Console. WnteLine(pw.BatteryLifePercent) 



http://www.ioprogrammo.it 



Dicembre 2007/ 13 ^ 



012-018:032-035 30-10-2007 15:35 Pagina 14 



COVER STORY T ■ Inviare SMS dal computer 




rapi 


.Disconnect() 


rapi 


.DisposeQ 


End If 


End Sub 



C'è quindi prima un controllo se il dispositivo è 
presente [DevicePresenf] poi la connessione (in 
questo caso sincrona con un timeout di 10 
secondi), la chiamata di una o più funzioni RAPI 
ed infine la disconnessione e la distruzione del- 
l'oggetto. 



LA CLASSE MESSAGE 

La classe Message ha una struttura semplice, 
una proprietà Text che rappresenta il testo del 
messaggio SMS e un insieme di oggetti 
Destinatario che rappresentano i destinatari del 
messaggio, questi oggetti sono a sua volta defini- 
ti nella classe Destinatario che contiene la pro- 
prietà PhoneNumber (numero di telefono del 
destinatario) e SendResult (risultato dell'invio) lo 
schema delle due classi (con i relativi attributi di 
serializzazione XML) è questo : 



Imports System. Xml. Serialization 




IMPOSTAZIONI 
DI SICUREZZA 



-^> 



L'ESECUZIONE 
DI RAPI 

I programmi che 

utilizzano RAPI, come 

quello descritto 

nell'articolo, possono 

non funzionare a 

causa delle 

impostazioni di 

sicurezza del 

dispositivo. 

In proposito è 

possibile consultare la 

sezione relativa di 

MSDN Library 

all'indirizzo 

http://msdn2 . m icrosoft 

■com/en-us/library/ms 

851423-aspx 



IL PROGETTO 

In Visual Studio 2005 creeremo una soluzione in 
C# o VB.NET che ospiterà due distinti progetti : 
una WindowApplication che girerà sul PC e una 
Console Application che girerà sullo 
Smartphone. 




Fig. 5: Progetto Console per Smartphone su Visual 
Studio 



La base della logica di comunicazione tra i due 
dispositivi sarà una classe che chiameremo 
Message che potrà essere serializzata in XML: 

1. Il PC crea un'istanza di Message dove mette 
numeri di telefono e testo del messaggio, la 
serializza su disco e la trasferisce come file allo 
Smartphone e avvia da remoto l'applicazione 
residente sul dispositivo 

2. L'applicazione sullo Smartphone deserializza 
il file ricevuto in un oggetto Message, invia gli 
SMS e contrassegna ogni indirizzo con l'esito 
dell'invio serializzando nuovamente la classe 
in un file 

3. A questo punto il PC recupera il file sullo 
Smartphone, deserializza nuovamente l'og- 
getto Message e legge i risultati. 

La base di tutto è quindi la classe Message che 
vedremo adesso in dettaglio 



<XmlRoot("message")> 



Public Class Message 



<XmlElement("destinatario")> 



Public Property Destinatarie) As List(Of 

Destinatario) 



End Property 



<XmlElement("text")> . 



Public Property TextQ As String 



End Property 



Friend Sub AddPhoneNumber(ByVal phoneNumber 

As String) 
'Aggiunge un numero di telefono creando un oggetto 

Destinatario 
' e lo inserisce in Destinatari 

End Sub 

Public Shared Function Deserialize(ByVal filename 
As String) As Message 
'Deserializza un oggetto Message da un file 

End Function 

Public Shared Function Serialize(ByVal m As 

Message, ByVal filename As String) As Boolean 
'Serializza un oggetto Message in un file 

End Function 
End Class 
Public Class Destinatario 



<XmlAttribute("phonenumber")> 



Public Property PhoneNumber() As String 



End Property 



<XmlElement("sendresult")> . 



Public Property SendResultQ As String 



End Property 



End Class 



COLLEGAMENTO 
A MESSAGE 

Abbiamo visto lo schema della classe Message e 
abbiamo detto che essa viene usata sia dall' ap- 



* 14 /Dicembre 2007 



http://www.ioprogrammo.it 



012-018:032-035 30-10-2007 15:35 Pagina 15 



Inviare SMS dal computer ■ T COVER STORY 



-0- 



plicazione sullo Smartphone che da quella sul 
PC. 

Poiché la classe deve essere identica per le due 
applicazioni (altrimenti le operazioni di serializ- 
zazione/deserializzazione potrebbero dare dei 
problemi) la cosa migliore da fare è: 

• inserire la classe in uno dei due progetti della 
soluzione 

• andare nell'altro progetto e scegliere aggiun- 
gi>elemento esistente 

• scegliere il file nella cartella del primo proget- 
to e nella finestra di dialogo scegliere aggiungi 
come collegamento come possiamo vedere in 
figura 6 




Fig. 6: Aggiunta del file come collegamento 



IL PROGRAMMA 
SULLO SMARTPHONE 

Prima di vedere il funzionamento dell'applica- 
zione su PC diamo uno sguardo a quella che 
andremo a creare sullo Smartphone. 
L'applicazione, che è ridotta a poche righe di 
codice, richiede come argomento il nome del 
file XML che il PC avrà creato sul dispositivo; 
l'applicazione deserializza questo file ed invia i 
messaggi utilizzando la libreria Microsoft 
WindowsMobile.PocketOutlook che avremmo 
aggiunto tra i riferimenti del progetto. 
L'intero codice del modulo si presenta quindi 
così: 

Imports Microsoft. WindowsMobile.PocketOutlook 
Module MainModule 

Sub Main(ByVal args() As String) 
If args.Length < 1 Then Return 
Dim requestFilename As String = "\Program 

Files\SmsSender\" & args(0) 
Dim responseFilename As String = 

IO.Path.ChangeExtension(requestFilename, 

".response") 
Dim msg As Message = 

Message.Deserialize(requestFilename) 
IO.File.Delete(requestFilename) 



For Each d As Destinatario In msg. Destinatari 

Try 

Dim phoneNumber As String = 

d.PhoneNumber 
Dim sms As New 

SmsMessage(phoneNumber, msg.Text) 
sms.SendQ 



d.SendResult = "ok" 



Catch ex As Exception 



d.SendResult = ex. Message 



End Try 



Next 



Message. Serialize(msg, responseFilename) 



End Sub 



End Module 



IL PROGRAMMA SUL PC 

Naturalmente le cose sono leggermente più 
complesse sul versante PC. L'applicazione sarà 
una Windows Application, tuttavia la finestra 
principale non sarà immediatamente visibile : 
apparirà un icona nel System Tray di Windows in 
modo da avere sempre la possibilità di accedere 
alle funzioni SMS. Per far questo la finestra sarà 
inizialmente non visibile, mentre verrà utilizza- 
to (nella form stessa) un controllo Notifylcon 
per gestire l'icona nel System Tray. Non ci 
addentreremo troppo nei particolari implemen- 
tativi, ci limiteremo a dire che ci sarà natural- 
mente un textbox per scrivere il numero di 
telefono da aggiungere ad una lista di numeri, 
una textbox per scrivere il testo dell' SMS e due 
bottoni che servono rispettivamente per chiu- 
dere la finestra o per inviare il messaggio. 



fiHiriVjtft 




Fig. 7: La form principale del programma 



COMUNICAZIONE 
CON IL DISPOSITIVO 

Più interessante è vedere come comunicare con 
il dispositivo. La libreria RAPI, che abbiamo già 
visto, consente di effettuare alcune operazioni 





SVILUPPO SU 

DISPOSITIVI 

MOBILI 

Benché Visual Studio 
metta a disposizione 
dei comodi emulatori 
per il test dei 
programmi su 
dispositivi mobili nella 
realtà il 

funzionamento nel 
mondo reale può 
essere a volte ben 
diverso. 

Il consiglio è quindi di 
testare sempre 
l'applicativo anche su 
apparecchi reali prima 
di rilasciarlo. 



http://www.ioprogrammo.it 



Dicembre 2007/ 15 ^ 



012-018:032-035 30-10-2007 15:35 Pagina 16 



COVER STORY T ■ Inviare SMS dal computer 




-e- 



per noi importanti: 

• di invocare un processo (cioè di avviare un pro- 
gramma) sul dispositivo remoto consentendo 
anche il passaggio di parametri 

• di trasferire un file dal PC al dispositivo 

• di trasferire un file dal dispositivo al PC 

• di cancellare un file dal dispositivo 

Per comodità noi abbiamo costruito una classe, 
chiamata Program, che contiene un oggetto RAPI 
dichiarato in modo condiviso {shared} ed una 
serie di metodi che "wrappano" le funzioni RAPI: 

Imports OpenNETCF. Desktop. Communication 
Public Class Program 

Private Shared _rapi As RAPI 
Friend Shared ReadOnly Property rapi() As RAPI 
' Istanza condivisa di RAPI 

Get 

If _rapi Is Nothing Then 

_rapi = New RAPI 
End If 
Return _rapi 

End Get 

End Property 

Private Shared Sub Connect() 

If Not rapi.Connected Then 

rapi.Connect(True, 100) 

End If 

End Sub 

Private Shared Sub Disconnect() 
If rapi.Connected Then 

rapi.Disconnect() 
End If 
End Sub 
Friend Shared Function GetDeviceProgramPath() 

As String 
' trova la cartella "Programmi" del dispositivo 
Connect() 

Dim result As String = _ 
rapi. GetDeviceSystemFolderPath(Environment. Special 

Folder.ProgramFiles) 
Disconnect() 
Return result 
End Function 

Friend Shared Sub WriteRemoteFile(ByVal 
localFilename As String, ByVal remoteFilename As 

String) 
' trasferisce un file sul dispositivo 
Connect() 
rapi.CopyFileToDevice(localFilename, 

remoteFilename, True) 
Disconnect() 
End Sub 

Friend Shared Sub 

WriteRemoteFileAndDelete(ByVal localFilename As 
String, ByVal remoteFilename As String) 



trasferisce un file sul dispositivo e lo cancella dal 



PC 



WriteRemoteFile(localFilename, 



remoteFilename) 



IO.File.Delete(localFilename) 



End Sub 



Friend Shared Sub TransferFileFromDevice(ByVal 
remoteFilename As String, ByVal localFilename As 

String) 
trasferisce un file sul dispositivo al PC 



ConnectQ 



rapi. Copy FileFromDevice(localFilename, 

remoteFilename, True) 
rapi.DeleteDeviceFile(remoteFilename) 



DisconnectQ 



End Sub 



Friend Shared Function ReadRemoteFile(ByVal 

remoteFilename As String) As String 
legge file sul dispositivo copiandolo prima sul PC 



Dim result As String 



ConnectQ 



If rapi.DeviceFileExists(remoteFilename) Then 
Dim localFilename As String = 

IO.Path.GetFileName(remoteFilename) 
Dim tempPath As String = 
Environment.GetFolderPath(Environment.SpecialFolde 

r.LocalApplicationData) 



localFilename 



IO.Path.Combine(tempPath, 
localFilename) 



rapi.CopyFileFromDevice(localFilename, 

remoteFilename, True) 
result = 
My.Computer.FileSystem.ReadAIIText(localFilename) 
End If 



DisconnectQ 



Return result 



End Function 



Friend Shared Function 
ReadRemoteFileAndDelete(ByVal remoteFilename As 

String) As String 

' legge file sul dispositivo copiandolo prima sul PC e 

cancellandolo dal dispositivo 



Dim result As String 



If rapi.Connected Then 



result = ReadRemoteFile(remoteFilename) 
If Not String. IsNullOrEmpty(result) Then 



ConnectQ 



rapi.DeleteDeviceFile(remoteFilename) 



DisconnectQ 



End If 



End If 



Return result 



End Function 



Friend Shared Sub ExitAppQ 



'Uscita dall'applicazione e distruzione di RAPI 



If rapi IsNot Nothing Then 



rapi.DisposeQ 



End If 



+ 16 /Dicembre 2007 



http://www.ioprogrammo.it 



012-018:032-035 30-10-2007 15:35 Pagina 17 



Inviare SMS dal computer ■ T COVER STORY 



-0- 



Application. Exit() 


End Sub 




Private Shared Sub Main() 


'Entry point dall'applicazione 


Application. Run(New 


FrmMain) 


End Sub 


End Class 



Try 



.CreateProcess(remoteProgramFilename, 
requestFilename) 



Il processo di invio dell' SMS nel dettaglio è que- 
sto: 

1. il programma PC recupera le informazioni 
(numeri di telefono e messaggio) e le serializ- 
za su disco locale in un file .request con un 
nome creato con una GUID. 

2. il programma PC trasferisce il file .request sul 
dispositivo, lo cancella dal disco locale, avvia 
da remoto il programma sullo Smartphone 
passandogli come parametro il nome del file 
.request e si mette in attesa (per un numero di 
secondi prefissato) che nel dispositivo remoto 
venga creato un file sesponse avente lo stesso 
nome. 

3. il programma sullo Smartphone deserializza 
in un oggetto Message il file .request, invia gli 
SMS ai destinatari e per ognuno di essi riporta 
l'esito dell'invio nella proprietà SendResult e 
infine serializza nuovamente Message in un file 
sesponse. 

4. a questo punto il programma PC, che era in 
attesa, si accorge che nel dispositivo è presen- 
te il file sesponse, lo trasferisce sul disco e 
riporta i risultati dell'invio. 

La cosa a prima vista può sembrare un po' mac- 
chinosa ma in realtà è l'unico modo che abbiamo 
per attendere che il processo sul dispositivo sia 
effettivamente terminato perché il metodo 
CreateProcess di RAPI non ci consente di attende- 
re il termine dell'esecuzione del processo stesso. 
Tutto il codice corrispondente sarà : 

Private Sub WaitQ 

'blocco applicazione per un secondo 

Application. UseWaitCursor = True 

Me.Cursor = Cursors.WaitCursor 

Threading.Thread.Sleep(lOOO) 

Application. UseWaitCursor = False 

Me.Cursor = Cursors. Default 
End Sub 
Private Function RemoteExecute(ByVal 

remoteProgramFilename As String, ByVal 

requestFilename As String, ByVal responseFilename 

As String, ByVal secondsWait As Integer) As Boolean 

'esecuzione del processo con attesa 

With Program. rapi 
.ConnectQ 



Catch ex As Exception 



MsgBox(ex. Message & vbNewLine & 

remoteProgramFilename) 



End Try 



For i As Integer = 1 To secondsWait 
If .DeviceFileExists(responseFilename) 

Then 



.DisconnectQ 



Return True 



Else 



WaitQ 



End If 



Next 



.DisconnectQ 



End With 



Return False 



End Function 



Private Function CreateMessageQ As Message 



'Creazione del Messaggio 



Dim msg As New Message 



For Each number As String In 

PhoneNumbers.Keys 
msg.AddPhoneNumber(number) 



Next 



msg.Text = Me.TxtSms.Text 



Return msg 



End Function 



Private Sub CreateAndSendMessageQ 



If PhoneNumbers.Count = Then 



MsgBox("Non ci sono numeri di telefono 
impostati!", MsgBoxStyle.Exclamation, "Errore") : 

Return 



End If 



If String. IsNullOrEmpty(TxtSms.Text) Then 
MsgBox("Non hai impostato il testo del 
messaggio!", MsgBoxStyle.Exclamation, "Errore") : 

Return 
End If 

Dim msg As Message = Me.CreateMessage 
Dim conversationlD As String = 

Guid.NewGuid.ToString("N") 
'nome del file xml usato per la richiesta 
Dim requestFilename As String = 

conversationlD & ".request" 
'nome del file xml usato per la risposta 
Dim responseFilename As String = 

conversationlD & ".response" 
Dim locaIRequestFilename As String = 

GetLocalTempFileName(requestFilename) 
Dim locaIResponseFilename As String = 

GetLocalTempFileName(responseFilename) 
If Message. Serialize(msg, 

locaIRequestFilename) Then 
'scrive il file nel dispositivo e lo cancella 

localmente 




http://www.ioprogrammo.it 



Dicembre 2007/ 17 ^ 



012-018:032-035 30-10-2007 15:35 Pagina 18 



COVER STORY T ■ Inviare SMS dal computer 





-0- 



Francesco Smelzo è 

specializzato nello 

sviluppo in ambiente 

Windows con 

particolare riferimento 

ad applicazioni in 

ambiente .NET sia 

web-oriented che 

desktop. 

Il suo sito web è 

www.smelzo.it . Come 

sempre è a 

disposizione per 

ricevere suggerimenti 

o richieste sull'articolo 

all'indirizzo di posta 

elettronica 

francesco@smelzo.it 



WriteRemoteFileAndDelete(localRequestFilename, 

GetRemoteFilePath(requestFilename)) 
Dim RemoteResponseFilePath As String = 

GetRemoteFilePath(responseFilename) 
'esegue il processo 
Dim execResult As Boolean = 
RemoteExecute(GetRemoteProgramFilename(), 
requestFilename, RemoteResponseFilePath, 60) 
If Not execResult Then 

MsgBox("Errore Esecuzione del 
processo!", MsgBoxStyle.Exclamation, "Errore") : 

Return 



End If 



'trasferisce il file .response dal dispositivo al 

pc host 
TransferFileFromDevice(RemoteResponseFilePath, 

locaIResponseFilename) 



'deserializza il messaggio 



msg = 

Message.Deserialize(localResponseFilename) 
'cancella il file .response nel pc host 
IO.File.Delete(localResponseFilename) 
'resetta la listView e l'insieme ElencoNumeri 
ElencoNumeri.Items.Clear() 



Me.PhoneNumbers 



New Dictionary(Of 

String, String) 



'riempie la listView con i risultati 
For Each ad As Destinatario In 

msg. Destinatari 
Dim li As ListViewItem = 
ElencoNumeri. Items.Add(ad.PhoneNumber, 0) 

N.Subltems.Add(ad.SendResult) 
Next 

Else 

MsgBox("Errore serializzazione del 
messaggio!", MsgBoxStyle.Exclamation, "Errore") : 

Return 

End If 

End Sub 



getto di avvio e premiamo F5. 
Nella System Tray scegliamo Send SMS ed impo- 
stiamo i numeri di telefono ed il messaggio 
(Figura 8) 



Il -IMBI 



:»o:: 



Vii w '^wi-v 



^m i 



Fig. 8: Impostazione dei numeri di telefono ed del 
messaggio 



Clicchiamo su Send e, dopo qualche secondo, 
dovremo vedere nella ListView il messaggio di 
conferma accanto ai numeri di telefono (Figura 




Conferma dell'invio 



ESECUZIONE 

DEL PROGRAMMA 

Per eseguire il programma occorre per prima 
cosa installare il progetto per lo Smartphone sul 
dispositivo, ciò è possibile semplicemente clic- 
cando con il tasto destro, in Visual Studio, sul 
progetto in Esplora Soluzioni, scegliendo la voce 
"Distribuisci" e indicando come destinazione il 
dispositivo attualmente connesso. 
Dopo questo passaggio esplorando il File system 
del dispositivo con ActiveSync dovremmo trova- 
re nel percorso "\Program Files\SmsSender" il 
programma SmsSender.exe. 

A questo punto impostiamo il progetto 
DesktopApp (il programma per PC) come prò- 



CONCLUSIONI 

In questo articolo abbiamo visto come controllare 
da remoto il dispositivo mobile, in questo caso per 
permettere l'invio di SMS da un PC collegato allo 
Smartphone. Il codice di esempio non è stilistica- 
mente perfetto (alcune problematiche potevano 
essere affrontate anche in maniera più elegante, 
ma ciò avrebbe comportato una minore com- 
prensibilità del codice) e mancano alcune funzio- 
ni lato desktop (ad esempio selezione da indirizzi 
di Outlook, possibilità di salvare e riutilizzare le 
liste di contatti ecc..) comunque può essere con- 
siderato come una base per prendere confidenza 
con la tecnica descritta. Al lettore il lavoro di adat- 
tamento e perfezionamento! 

Francesco Smelzo 



+ 18 /Dicembre 2007 



http://www.ioprogrammo.it 



020-023:032-035 30-10-2007 15:39 Pagina 20 



ioProgrammo Web T ■ Interfacciare PHP con Gmail 



PHP INCONTRA 
GOOGLE MAIL 

HAI MAI PENSATO DI USARE GMAIL COME ARCHIVIO FTP? TI PIACEREBBE ACCEDERE ALLA POSTA 
DIRETTAMENTE DA UNA TUA WEB APPLICATION PHP? TI PRESENTIAMO LA LIBRERIA CHE TI 
CONSENTE DI FARE TUTTO CIÒ. POCHE RIGHE DI CODICE E GMAIL NON AVRÀ PIÙ SEGRETI! 




-0- 




tM.WM.UMU.lUm 

conoscenza di base di 
PHP 



PHP, Apache,Libgmail 



Tempo di realizzazione 



Tra le tante librerie di cui Php dispone per l'in- 
terazione con diverse tipologie di software, in 
quest'articolo concentreremo l'attenzione su 
una in particolare: Libgmailer, collezione di funzio- 
ni scritta per integrae PHP con Gmail. Vedremo 
come connetterci, come fare il login alla casella di 
posta elettronica, creare l'oggetto Gmailer , preleva- 
re e-mail inviate, inviare noi stessi delle e-mail. 
Dopo aver spiegato il funzionamento, sulla base 
delle conoscenze acquisite, svilupperemo una pic- 
cola applicazione. 



00 



DELLA LIBRERIA 

LibGmailer consente di connettersi al sito di Gmail e 
ricercare le informazioni richieste dall'utente, effet- 
tuando, in maniera automatica, le operazioni di 
login, gestendo tutte le operazioni possibili con un 
servizio di webmail, compresa la selezione di mes- 
saggi da prelevare in base a determinati attributi, 
come per esempio la suddivise in categorie o la sele- 
zione di messaggi flaggati (con star o label) in modo 
da poter essere contraddistinti. In maniera più ana- 
litica, Gmailer, la classe su cui lavoreremo (la quale è 
una classe funzionale e dunque ha bisogno che le 
sue funzioni siano integrate in un'applicazione 
completa per poter ottenere un risultato) si preoc- 
cupa di scrivere, comporre, salvare bozze, inviare, 
applicare etichette alle e-mail, ma anche di rimuo- 
verle, applicare la stella di Gmail, rimuoverla, carica- 
re e scaricare attachment: tutto questo per quel che 
riguarda la gestione delle e-mail. La prima cosa che 
Gmailer fa per noi è quella di connettersi a Gmail: 
per portare a termine questo processo e "armeggia- 
re" con il traffico http/https, essa utilizza l'estensione 
curi di php, senza cui non funzionerebbe. 



CHE COS'È CURL? 

Curi sta per Client- Uri e serve per il trasferimento di 
file attraverso la sintassi Uri, che supporta i proto- 



colli Ftp, Ftps, Http, Https, Tftp, Telnet e altri ed è uti- 
lizzato quando bisogna andare a ritrovare contenuti 
all'interno di siti web e prelevare o, comunque, 
scambiare dei file. Affinché esso sia utilizzato in 
ambiente Php, è necessario attivarne l'estensione. 
Le operazioni per fare questo sono davvero molto 
semplici. Innanzitutto bisogna che il pacchetto Curi 
sia installato e, affinché funzioni su Php, esso deve 
essere almeno nella versione Curi 7.0.2-beta. Se stia- 
mo usando una versione di Php successiva alla 4.2.3, 
bisogna che la versione Curi sia la 7.9.8. Per poter 
utilizzare tale supporto, occorre compilare Php con 
l'opzione 

-with-curl[=DIR], 

dove DIR sta per la directory che contiene le direc- 
tory di tipo lib e include. Se stiamo usando una ver- 
sione di Php successiva alla 4.3.0, invece, possiamo 
configurare Ph all'uso di curi per gli Uri stream 

— with-curlwrappers 

Se siamo utenti Windows, dobbiamo abilitare il tutto 
copiando Iibeay32.dll e ssleay32.dll dalla directory 
PHP/Win32 alla cartella di Windows 
C:\\Windows\system32 o C:\\Winnt\system. 



L'UTILIZZO 

DI LIBGMAILER 

Come utilizzare allora la libreria? Come si interagi- 
sce con essa? Costruiamo insieme il codice necessa- 
rio a sfruttare le sue funzionalità e a renderla opera- 
tiva. La prima operazione che eseguiremo sarà quel- 
la di prelevare un'e-mail, che sceglieremo in base ad 
un'etichetta definita dall'utente. 
Proviamo per prima cosa a prelevare un'e-mail che 
abbiamo etichettato come Label: questa semplice 
applicazione ci permetterà di approfondire come 
richiamare la classe GMailer, come effettuare la con- 
nessione, prelevare i dati di login per Gmail e fare i 
controlli per individuare se ci sono problemi di 



* 20 /Dicembre 2007 



http://www.ioprogrammo.it 



020-023:032-035 30-10-2007 15:39 Pagina 21 



Interfacciare PHP con Gmail 



T ioProgrammo Web 



installazione o problemi con la connessione. 



<?php 



require("include/libgmailer.php"); 



-0- 



require("include/config.php"); 

Oltre al tag che contraddistingue l'inizio di porzione 
di codice php, provvediamo al richiamo dei file che 
ci servono: la libreria libgmailer.php e un file 
conflg.php, nella cartella include Libgmailer si trova 
facilmente in rete ( ad esempio 
http://sourceforge.net/project/showfiles.php7group id=1 
16304 dove è presente la versione 0.9.0 beta 8 ). A 
cosa serve config.php? è un file di configurazione 
che permette di memorizzare i nostri dati per F au- 
tenticazione come utente di Gmail. Nel box ad esso 
dedicato c'è il semplice codice che lo compone. 

$gm = new GMailer(); 
if (!$gm-> createci) { 

Creiamo ora l'oggetto GMailer: 

die("Non è stato possibile creare l'oggetto Gmailer: 

".$gm->lastActionStatus()); 
} else { 

il costruttore, così come è stato strutturato, farà un 
controllo per verificare se l'estensione Curi è dispo- 
nibile o meno. Da ciò l'importanza della sua abilita- 
zione come sottolineato nelle premesse. Poiché non 
abbiamo un dato di output che ci riveli l'avvenuta 
creazione, dobbiamo accertarci di questo con il 
metodo GMailer: :$created. Nel caso di fallimento, 
mandiamo un messaggio di errore usando il metodo 
lastActionStatusQ che descrive, con una stringa, il 
problema (nello specifico, nel caso in cui si fosse 
verificato il problema il messaggio sarebbe stato "no 
curi") . 

$gm->setl_oginInfo($user, $password, $timezone); 



La prima operazione è quella di connettersi, su que- 
sta porazione facciamo subito un controllino per 
vedere se la connessione è andata a buon fine se fal- 
lisce salta alla fine stampando il messaggio di erro- 
re ricevuto in output da lastActionStatusQ . Se tutto 
va bene, invece, utilizza il metodo 
GMailer::$fetchBox per prelevare il risultato di una 
ricerca il cui argomento è di tipo GM_LABEL e che 
viene settato nel secondo parametro del metodo. Il 
terzo parametro di input, invece, rappresenta dove il 
cursore si deve posizionare per effettuare il prelievo: 
visto che a noi interessava tutto il contenuto, lo 
abbiamo settato a 0. A questo punto possiamo 
richiamare il metodo GMailer: igetSnapshot che si 
preoccupa di fornire un oggetto di tipo snapshot, 
creato appositamente per strutturare i risultati della 
query creata avendo come argomento GM_LABEL. 
Se questo è stato fatto, contiamo infine il numero 
degli snapshot trovati con l'etichetta e mandiamoli 
in output. 



VARI TIPI DI FETCH 

Approfondiamo ora il discorso.. Il codice di prima ci 
ha permesso di prendere un tantino dimestichezza 
con la libreria introducendo il discorso della fetch. 
Creare un'applicazione per fare una fetch solo sulle 
label può essere limitativo, pertanto ci cimenteremo 
subito in qualcosa di più completo. Il metodo ietch- 
box() permette, di volta in volta, grazie all'uso di 
diverse costanti, di impostare i parametri che servi- 
ranno a diversificare i tipi di prelievo: GM_STAN- 
DARD per prelevare tutti gli standard box {Inbox, 
Sent, Ali, Starred, Spam e Trash), GM_LABEL per pre- 
levare le e-mail che vengono identificate da una 
determinata etichetta, GM_QUERY per impostare 
una query, età. Il metodo infatti è del tipo: 
GMailer::$fetchBox(parl, par2, par3), dove pari è la 
costante che identifica il tipo a cui appartiene par2. 
Del terzo abbiamo già detto. 




Se l'operazione è andata a buon fine , possiamo 
acquisire le informazioni di login, settate nel file 
conflg.php . Passiamo ora al prelievo vero e proprio! 

if ($gm->connect()) { 

$gm->fetchBox(GM_LABEL, "label", 0); 
$snapshot = $gm->getSnapshot(GM_LABEL); 
if ($snapshot) 

print( "Numero totale delle conversazioni 
con la mia etichetta = " . 

$snapshot->box_total); 

} else { 

die("La connessione è fallita perché 
M .$gm->lastActionStatus()); 



require("include/libgmailer.php"); 



require("include/config.php"); 



$gm = new GMailerQ; 



if (!$gm->created) { 



die("Non è stato possibile creare l'oggetto 

Gmailer: n .$gm->lastActionStatus()); 



} else { 



$gm->setl_oginInfo($user, $password, 

$timezone); 
if ($gm->connect()) { 

Quella precedente è la prima parte che abbiamo già 
descritto, per cui possiamo passare subito alla parte 
nuova. 



switch ($Che_operazione_vuoi_fare) { 



http://www.ioprogrammo.it 



Dicembre 2007/ 21 ^ 



020-023:032-035 30-10-2007 15:39 Pagina 22 



ioProgrammo Web T I Interfacciare PHP con Gmail 




case 1: 



$gm->fetchBox(GM_STANDARD, "inbox", 0); 



$snapshot ■■ 
break; 



$gm->getSnapshot(GM_STANDARD); 



Il codice prevede la possibilità di scegliere quale 
operazione effettuare mediante uno switch. 
Il caso 1 usa la costante GM_STANDARD che viene 
impostata ad inbox: questo vuol dire che chiediamo 
di prelevare tutto il contenuto della Inbox dell'ac- 
count. 

case 2: 

$gm->fetchBox(GM_LABEL, "myjabel", 0); 
$snapshot = $gm->getSnapshot(GM_LABEL); 
break; 



MANDIAMO UN'EMAIL 

Utilizziamo ora il metodo GMailer::$send per invia- 
re un'email dall'account Gmail. 
Il metodo restituisce un valore booleano per con- 
trollare l'avvenuto invio della mail, che può essere 
utilizzato insieme a lastActionStatusQ, come abbia- 
mo già fatto precedentemente. SendO accetta come 
parametri di input tutti i normali componenti di 
un'email: a chi inviare (A:, Ce, Ccn:), il soggetto del 
messaggio, il messaggio stesso, allegati, e via di 
seguito. Descriviamo un esempio di implementa- 
zione che ne faccia uso. 

Dopo aver definito gli include, creato la Gmailer e 
impostata la connessione (il cui codice è analogo 
alle parti precedenti) , modifichiamo il codice a par- 
tire dal punto (1). 



-e- 



Il case 2 si occupa invece di ricercare tutte le e-mail 
che sono etichettate come myjabel, il cui tipo è 
definito dalla costante GM_LABEL. 

case 3: 

$gm->fetchBox(GM_QUERY, "From: friend 

@domain.it", 0); 
$snapshot = $gm->getSnapshot(GM_QUERY); 
break; 

Analogamente, il case 3, il cui compito è processare 
la query tra virgolette e ricercare tutte le e-mail che 
sono state mandate da quell'indirizzo. 

case 4: 
$gm->fetchBox(GM_CONTACT, "ali", 0); 



$snapshot = 
break; 



$gm->getSnapshot(GM_CONTACT); 



Infine, agiamo sulla rubrica: il risultato di questa 
fetch è uno snapshot contenente i dati delle persone 
che abbiamo nella nostra rubrica Gmail. 

default: 

die(); 



} 



Infine, se nella nostra interfaccia grafica che 
interagisce con il codice php non è stata fatta 
nessuna scelta che sia contemplata nello switch, 
il processo viene interrotto e si esce dal pro- 
gramma. Le righe che seguono sono di conclu- 
sione e sono stata già commentate nel prece- 
dente paragrafo. 

else { 
print("l_a connessione è fallita 

perché ".$gm->lastActionStatus()); 
} 



$to = "a_chi_inviare 

©dominio. com, amico@azienda.com"; 
$subj = "Invio di un'email con attachment"; 
$message = "E' arrivato?"; 
$cc = "a_chi_inviare2 @dominio.it"; 
$attachments = array("path/file.ext ", "path/file2.ext "); 

Abbiamo definito le variabili che useremo per l'im- 
put del metodo: notiamo come siano passate tutte 
quante come stringhe, mentre solo $attachments è 
un array. 

$gm->send($to, $subj, $message, 
$cc, "", "", "", $attachments, false); 
} else { 

print("La connessione è fallita perché 

M .$gm->lastActionStatus()); 



} 



Richiamiamo ora la sendQ\ il codice mostra il pas- 
saggio dei parametri: è importante sottolineare 
come sia fondamentale l'ordine delle variabili e che, 
nel caso qualcuno non dovesse essere specificato, 
bisogna inserire una stringa vuota. L'unico parame- 
tro che non abbiamo definito con una variabile è il 
false alla fine. A cosa serve? A impostare l'invio della 
e-mail oppure a conservarla come drajt. false sta 
per "invia e-mail subito" true invece come "salvala 
in draft'. 

CONCLUSIONI 

La libreria è semplice quanto potente, e può 
essere utilizzata in diversi contesti, l'unica diffi- 
coltà potrebbe essere relativa alla comprensione 
delle costanti che fanno da interfaccia verso i 
comandi di Gmail, ma con un po' di pazienza la 
curva di apprendimento non sarà particolar- 
mente complessa 

Caterina Patrizia Morano 



► 22 /Dicembre 2007 



http://www.ioprogrammo.it 



020-023:032-035 30-10-2007 15:39 Pagina 23 



Interfacciare PHP con Gmail 



T ioProgrammo Web 



-e- 




'N'APPLICAZIONE COMPLETA IN SOLI TRE FILE 



Vediamo ora come inserire in un 
esempio completo la parte di codice 
che abbiamo appena descritto. L'ap- 
plicazione permette di fare il login 
inserendo user name e password in 
un form per andare a prelevare e far 
vedere tutti i nomi dei contatti che 
abbiamo nella rubrica. Una volta vi- 
sualizzati è possibile scegliere quelli 
a cui si intende inviare una e-mail ed 
effettuare la spedizione. 
Vediamo come funziona nel detta- 
glio. L'applicazione è distribuita in 
tre file .php: 

test_ioprogrammo.php, contatti. php 
e invia email. php. La prima visualiz- 
za due text-box per l'inserimento di 
user name e password, così da poter- 
si loggare eventualmente anche con 
più account, qualora si voglia. Dopo 
aver cliccato su pulsante VAI! si vie- 
ne richiama il file Contatti. php che si 
occupa del prelievo e della visualiz- 
zazione dei tutti i contatti che ci so- 
no nella rubrica di gmail. I contatti 
vengono ordinati alfabeticamente e 
su ogni riga, oltre al radio button 
per la selezione, appare, in ordine, 
l'indirizzo e-mail e il nome del con- 
tatto: basta scegliere a chi spedire e 
cliccare sul tasto Invia le gmails. In 
questo modo verrà richiamato il ter- 
zo e ultimo file invia email. php per 
la creazione dell'email e la spedizio- 
ne. 
Di seguito i tre files. 

test ioprogrammo.php 

<html> 
<head> 



Proviamo la libreria Libgmailer 



</head> 



<body> 



<table border="l"> 



<tr> 



<td> 



<form method = "post" 

action="Contatti.php"> 



<table> 



<tr> 



<td>Username</tdxtd>< input 
type="text" name="user" /></td> 



</tr> 



<tr> 



<td> Password </tdxtd>< input 
type= "password" name="password" 
/></td> 



</tr> 



<tr> 



echo "<tr>"; 



<td colspan="2"xinput 
type="submit" value="Vai!" /></td> 



</tr> 



echo '<tdxinput 
type="checkbox" name="emails[]" 
value="'.$row['emair].'" 
checked = "checked7></td>'; 



</table> 



</form> 



echo 

'<td>'.$row['emair].'</td>', 



</td> 



</tr> 



echo 

'<td>'.$row['name'].'</td>', 



</body> 



echo "</tr>\n\n"; 



</html> 

contatti. php 

<?php 



?> 



</table> 



include('include/libgmailer.php'); 
if((isset($_POST['user'])) && 

(isset($_POST['password']))) { 



<input type="submit" value="Invia le 

gmails" /> 



$gm = new GMailerQ; 



if ($gm->created) { 



</form> 

Invia gmail. php 

<?PHP 



$gm- 
>setl_oginInfo($_POST['user'], 
$_POST['password'] / 0); 



require("include/libgmailer.php"); 



$gm = new GMailer(); 



if (!$gm->created) { 



if ($gm->connect()) { 



$gm- 
>fetchBox(GM_CONTACT, "ali", "") 



die("Non è stato possibile creare 

l'oggetto Gmailer: ".$gm- 

>lastActionStatus()); 



$snapshot = $gm- 
>getSnapshot(GM_CONTACT) 



$returned_emails = 
$snapshot->contacts 



} else { 



if ($gm->connect()) { 



$subj 



"E-mail di 

prova" 



} else { 



$message = "Ecco il 
testo dell'e-mail"; 



die("Connessione 
fallita: M .$gmailer->lastActionStatus()); 



$cc = 
"altrocontatto@indirizzo.it"; 



> 



} else { 



$attachments = 
array("index.php"); 



die("Non posso creare la 
classe: M .$gmailer->lastActionStatus()); 



foreach 
($_POST['emails'] as $email){ 



> 



> 



?> 



$gm- 
>send($email, $subj, $message, $cc, "", "", 
"", $attachments, false); 



<html> 



<body> 



> 



<form method = "post" 

action = "invia_email. php" > 



} else { 



<table border="l"> 



<tr> 



print("La 
connessione è fallita perché ".$gm- 
>lastActionStatus()); 



<tdx/td> 



<td>Email</td> 



> 



<td>Nome Contatto</td> 



</tr> 



print("Le gmail sono 

state mandate!!!"); 



<?php 



foreach($returned_emails as $row){ 



?> 



http://www.ioprogrammo.it 



Dicembre 2007/ 23 ^ 



028-032:032-035 30-10-2007 15:43 Pagina 28 



ioProgrammo Web T ■ Design Pattern in PHP 



PHP AD OGGETTI 
TECNICHE AVANZATE 

I DESIGN PATTERN RAPPRESENTANO I PILASTRI FONDAMENTALI DI UN PROGETTO DESTINATO 
AL SUCCESSO. ESSI COSTITUISCONO IL CUORE PULSANTE DELLA PROGRAMMAZIONE ORIENTATA 
AGLI OGGETTI. VEDIAMO COME IMPLEMENTARNE ALCUNI IN PHP 5 



^ 




□ CD CJ WEB 

PHP-Design-Patterns.zip 



n 




REQUISITI 



I ' Il IM I ^ 

Medie di OOP e PHP 5 



PHP, Apache HTTP 
server 



Tempo di realizzazione 



0000 



In un articolo precedente abbiamo visto alcu- 
ne delle caratteristiche avanzate di PHP 5. In 
particolare si è visto come implementare 

alcuni metodi speciali, come set, gei e cali. 

Inoltre, abbiamo illustrato alcune caratteristiche 
orientate agli oggetti (OO) implementando due 
interfacce particolari, ossia ArrayAccess e Iterator. 
La prima per eseguire l'overload dell'operatore 
utilizzato dagli array, ossia la parentesi quadra [], 
mentre la seconda per rendere la nostra classe 
"traversatole". 

In quest'articolo ci accingiamo ad esaminare il 
cuore della programmazione OO, ossia i design 
pattern. Infatti, visto che PHP ha introdotto la 
programmazione orientata agli oggetti (OOP) 
solo nella versione 5, molti programmatori PHP 
non sono a conoscenza di questi straordinari 
strumenti che rendono più semplice la vita del 
programmatore. Alla fine del presente articolo il 
lettore saprà: 

• Cosa sono i design pattern. 

• Come implementare, in PHP, alcuni dei pattern 
più comuni. 



DESIGN PATTERN 

Chiariamo subito che non è possibile analizzare, 
in modo approfondito, i design pattern in un sin- 
golo articolo. Basti pensare che vi sono interi libri 
dedicati all'argomento. Tuttavia, cercheremo di 
ridurre al minimo buona parte della teoria e ren- 
dere l'articolo quanto più pratico possibile. Chi 
vuole approfondire l'argomento, ad ogni modo, 
troverà diversi libri in commercio, come il classi- 
co della Gang of Four (vedi box). 
Alla voce design pattern Wikip e dia recita così: 
"Nell'ingegneria del software, un design pattern 
può essere definito 'una soluzione progettuale 
generale ad un problema ricorrente'. Esso non è 
una libreria o un componente di software riusa- 
bile, quanto una descrizione o un modello da 
applicare per risolvere un problema che può pre- 



sentarsi in diverse situazioni durante la progetta- 
zione e lo sviluppo del software. 
La differenza tra un algoritmo e un design pat- 
tern è che il primo risolve problemi computazio- 
nali, mentre il secondo è legato agli aspetti pro- 
gettuali del software". 

In pratica un design pattern è una soluzione 
rodata ad un problema ricorrente. Se siete degli 
esperti programmatori in un linguaggio orienta- 
to ad oggetti, è molto probabile che abbiate già 
usato un design pattern senza saperlo. Andiamo, 
ora, ad esaminare alcuni dei pattern più comuni 
e vediamo come implementarli in PHP. 



STRATEGY PATTERN 

Per presentare lo strategy pattern facciamo subi- 
to un esempio. Supponiamo di dover implemen- 
tare diversi algoritmi di ordinamento e di usare 
l'uno o l'altro a seconda la situazione. In questo 
caso quale sarebbe la cosa più ovvia da fare? 
Nella programmazione procedurale verrebbe 
naturale implementare diverse funzioni (una per 
ogni algoritmo) con diversi nomi ed invocare 
quella adatta a seconda il contesto. Il fatto è che 
noi siamo programmatori che utilizzano l'OOP e 
quindi optiamo per una soluzione più flessibile. 
In pratica usiamo un'interfaccia (o una classe 
astratta) con un metodo, sort, e diverse classi che 
implementano tale interfaccia. Ci saranno tante 
implementazioni quanti algoritmi. Tutto ciò è 
illustrato dal class diagram di figura 1. 

A livello di codice poi scriviamo qualcosa del 
genere: 

$sorter = new BubbleSorter(); 

[■■■] 

$sorter->sort($elements); 

Supponiamo, ora, che un giorno ci accorgiamo di 
aver scelto un algoritmo di sorting meno effi- 
ciente. In questo caso ci basterà intervenire sulla 



+ 28 /Dicembre 2007 



http://www.ioprogrammo.it 



028-032:032-035 30-10-2007 15:43 Pagina 29 



Design Pattern in PHP 



T ioProgrammo Web 



-e- 











■:■■■■■: 

..riiln .■ m - ■ -r. i. B.-.J 






1 1 


. ■ i-C h 


ha d :■ ■ i 






^^ib^-t- -> i^. ■■ ^» 


^-. r iU^-t-^i^ ■■ ^- 



F/gf. 1: Class diagram dello strategy pattern per il sor- 
ting. 



creazione dell'istanza della classe che imple- 
menta l'algoritmo e la parte restante possiamo 
lasciarla inalterata. In termini di codice abbiamo: 

$sorter = new QuickSorter(); 
// Tutto il resto rimane inalterato 

Ciò che abbiamo fatto, nella letteratura dei desi- 
gn pattern, ha un nome ben preciso ed è lo stra- 
tegy pattern. Secondo la Gang of Four, lo scopo 
dello strategy pattern è: 

"Definire una famiglia di algoritmi, incapsulare 
ognuno di essi e renderli intercambiabili. Lo stra- 
tegy permette di modificare i vari algoritmi in 
modo indipendente dal codice client che li usa". 
In pratica, lo strategy si usa quando vi è la neces- 
sità di gestire diverse implementazioni di ciò che 
è, a livello concettuale, lo stesso algoritmo. Nel 
nostro esempio, concettualmente ci serviva ordi- 
nare un insieme di elementi. L'algoritmo, dun- 
que, è lo stesso. Le implementazioni, tuttavia, 
sono più di una, ossia bubble sort, quick sort, 
merge sort e così via. 

Terminiamo il paragrafo sullo strategy pattern 
con un interrogativo. Supponiamo che vi chieda- 
no di implementare un algoritmo che permette 
di criptare un testo. Per fare ciò vi sono diversi 
algoritmi di crittografia (DES, Blowfish, ecc.). 
Ovviamente, deve esserci la possibilità di cam- 
biare l'algoritmo di crittografia usato senza stra- 
volgere il codice. Vi viene in mente qualche pat- 
tern di vostra conoscenza che vi permette di 
risolvere il problema in modo elegante? 



FACTORY PATTERN 

Il codice precedente, in realtà, viola un altro prin- 
cipio fondamentale di design. In pratica un pro- 
getto dovrebbe essere "aperto" alle estensioni ma 
"chiuso" alle modifiche. Sto parlando del cosid- 
detto Open-Closed Principle (OCP). Ad un primo 
acchito questo principio può sembrare contrad- 
dittorio. In realtà, se capito ed applicato può por- 
tare a progetti molto robusti ed ampiamente 
manutenibili. Come abbiamo violato l'OCP nel- 



l'esempio di sorting precedente? Lo abbiamo 
fatto in fase di creazione dell'istanza concernen- 
te l'algoritmo di ordinamento scelto. Infatti, in 
un caso reale la scelta dell'algoritmo sarebbe 
probabilmente gestita tramite una variabile glo- 
bale o, preferibilmente, un file di configurazione 
o qualche altra tecnica che, ad ogni modo, com- 
porterebbe un codice simile al seguente: 

$sorter = nuli; 

if($sortingAlgorithm == "quick") 
{ 



$sorter = new QuickSorterQ; 



} 



else if($sortingAlgorith == "bubble") 



{ 



$sorter = new BubbleSorterQ; 



> 



else 



[-] 



$sorter->sort($elements); 

Possiamo riformulare l'OCP con la seguente 
frase: "Identifica la parte del tuo codice che cam- 
bia ed incapsulala". Nel codice precedente la 
parte che rimane uguale è l'invocazione del 
metodo sort Tutta la parte precedente, invece, ha 
una buona probabilità di cambiare. Supponete, 
ad esempio, che in futuro si scopra un algoritmo 
di ordinamento più efficiente. In questo caso 
dovreste aggiungere un altro else al blocco appe- 




ME INIZIARE 



Per provare il codice allegato a 
quest'articolo avete bisogno di 
PHP versione 5.2.* ed un Web ser- 
ver. 

Il primo lo potete trovare qui: 
http://www.php.net/ 

Come Web server io ho utilizzato 
Apache HTTP Server che potete 
trovare all'indirizzo: 

http://httpd.apache.org/ 




GANG OF FOUR 
(GOF) 

La Gang of Four 
(banda dei quattro) o, 
in breve, GoF è il 
simpatico nomignolo 
con cui ci si riferisce 
spesso ai quattro 
autori del libro 
"Design Patterns: 
Elements of Reusable 
Object-Oriented 
Software" (ISBN 0-201- 
63361-2). Gli autori 
sono: Erich Gamma, 
Richard Helm, Ralph 
Johnson, e John 
Vlissides. Sono 
considerati i pionieri 
dei design pattern in 
quanto i primi a 
portare il concetto di 
pattern, già presente 
in architettura, nel 
mondo dell'ingegneria 
del software. 



Se utilizzate Windows e volete 
un'installazione molto semplice di 
PHP ed Apache Web server consi- 
glio di utilizzare EasyPHP. Esso in- 
stalla, in un colpo solo, PHP, Apa- 
che Web server, MySQL e 
PHPMyAdmin. Questi ultimi due 
non vi serviranno per gli esempi 
di questo articolo, ma vi saranno 
ad ogni modo utili per provare 
script che utilizzano il database 
MySQL. L'indirizzo per EasyPHP è il 
seguente: 



http://easyphp.org/ 

Una volta installato ed avviato il 
server, potete provare gli script al- 
legati utilizzando un URL simile al 
seguente: 

http://localhost/ioprogrammo/php5/ad - 

vanced-oop/design- 

patterns/Observer/client.php 

Il precedente URL è valido se ave- 
te impostato Apache HTTP Server 
in ascolto sulla porta 80 (di de- 
fault è così) e messo il codice alle- 
gato sotto il path 
ioProgrammo/php5/advanced- 
oop/design-patterns, che a sua 
volta va inserito sotto la root pun- 
tata da localhost. Se avete usato 
EasyPHP, il path completo sarà 
qualcosa del genere: 
C:\Programmi\EasyPHP 
2.0b1\www\ioProgrammo\php5\ad 
vanced-oop\design-patterns\Ob- 
server 



http://www.ioprogrammo.it 



Dicembre 2007/ 29 ^ 



028-032:032-035 30-10-2007 15:43 Pagina 30 



ioProgrammo Web T I Design Pattern in PHP 




RISORSE UTILI 

PHP Home Page: 

http://www.php.net/ 

Manuale online per 

PHP 5: 

http://it.php.net/manual/ 

en/language.oop5.php 

Design Pattern 

(Wikipedia): 

http://it.wikipedia.org/wi 
ki/Design pattern 



-0- 



na visto. Ciò che conviene fare, a questo punto, è 
isolare quel pezzo di codice (il blocco if-else) ed 
incapsularlo all'interno di una classe che, in ter- 
mini di design pattern, prende il nome di classe 
factory. Così facendo, inoltre, rispettiamo anche 
il Single Responsibility Principle (SRP), ossia la 
classe factory ha la singola responsabilità di crea- 
re l'istanza del sorter opportuno. Assieme allo 
strategy, il factory pattern è quello che si utilizza 
più frequentemente. 
Ecco il codice della nostra classe factory: 



class SorterFactory 


{ 


private static $algorithms = array("bubble", 

"quick"); 




static function create($name) 


{ 


if (!in_array($name, 

self::$algorithms)) 


{ 


throw new 
Exception("L'algoritmo $name non è presente"); 


} 


switch ($name) 


{ 


case "bubble": return 
new BubbleSorter($name); 


case "quick": return 
new QuickSorter($name); 


} 


} 


} 



In pratica, il metodo create, prende in ingresso il 
nome dell'algoritmo da utilizzare. Se tale algorit- 
mo non è presente lancia un'eccezione altrimen- 
ti, ritorna un'istanza dell'algoritmo desiderato. 
Vediamo, ora, il codice client che utilizza la clas- 
se factory appena vista: 











\1*I1 ■ 


:_■■.--.■-. 


1 1 1 

1 u 


iljir Ir ■■■; ■ i 1 
i i ■■ 1 . 1 1 j i i ii ii 
I.'J A*. 




■. F -: j 1 u| : :-:\i 


f 




i" 


1! i i i i il 1 j i ii 


i | i ■ 1 "i" ili 


<. >"i: yh^ji.-i-gI 




.l.il'ir Ir ■■■; ■ i 1 
■ liliali. 1 1 j i i n ii 
i i 1 l.'i i ■ 







$elements = array("Alessandro Lacava", "Domenico 
Morda'", "Antonino Catanese"); 

[■■■] 

$sorter = SorterFactory: :create("bubble"); 
$sorter->sort($elements); 



[-] 



Come potete vedere per usare, ad esempio, il 
quick sort vi basta cambiare il parametro bub- 
ble in quick e tutto il resto del codice può rima- 
nere inalterato. 

Inoltre, per rendere disponibile un altro algo- 
ritmo ci basterà implementare l'interfaccia 
Sorter ed aggiungere il codice di creazione in 
un solo punto, ossia nel metodo create della 
classe factory. 



OBSERVER PATTERN 

Un altro pattern molto utile è il cosiddetto 
Observer Pattern. Il class diagram semplificato 
di figura 2 ne illustra il design. 
Ed ecco la definizione: 

"L'observer pattern definisce una dipendenza 
uno-a-molti tra oggetti, tale che quando un 
oggetto muta il suo stato, tutti gli oggetti che 
dipendono da esso sono notificati ed aggiorna- 
ti automaticamente". 

Formalismi a parte, tramite l'observer pattern 
possiamo creare un sistema event-driven in 
cui alcune entità dimostrano il loro interesse al 
verificarsi di un certo evento. 
Un esempio classico è quello della Borsa. 
Vogliamo fare in modo che quando il prezzo di 
un'azione cambia alcuni investitori siano noti- 
ficati. Il numero d'investitori da avvertire, 
ovviamente, è soggetto a cambiare nel tempo 
quindi dovremo sviluppare un sistema che, in 
modo flessibile, ci consentirà di aggiungere o 
rimuovere investitori. 

L'observer pattern ci permette di risolvere il 
problema in modo elegante. Riferendoci alla 
figura 2, nel nostro esempio il subject astratto 
è la classe Azione, un subject concreto è rap- 
presentato dalla classe AzioneConcretaFittizia, 
l'observer astratto è costituito dall'interfaccia 
Ilnvestitore, mentre l'observer concreto è rap- 
presentato dalla classe Investitore. Vediamo di 
analizzare il codice che implementa tale pat- 
tern. 

L'interfaccia Ilnvestitore è molto semplice: 



Fig. 2: Class diagram dell'observer pattern. 



interface Ilnvestitore 


{ 




function update(Azione 


$obj); 


} 



* 30 /Dicembre 2007 



http://www.ioprogrammo.it 



028-032:032-035 30-10-2007 15:43 Pagina 31 



Design Pattern in PHP ■ T ioProgrammo Web 



-e- 



Essa espone un solo metodo, update. Notate che 
abbiamo usato un "hint" (vedi box) per specifi- 
care che il metodo accetta solo oggetti di tipo 
Azione. La classe concreta che implementa tale 
interfaccia è Investitore: 

class Investitore implements Ilnvestitore 

S 

private $nome; 



private $azione; 



function construct($name) 



{ 



$this->name = $name; 



function update(Azione $azione) 



{ 



echo "<b>Notifica per $this->name:</b> 

echo "Il prezzo attuale di ". $azione- 
>getSimbolo(). " è " . $azione->getPrezzo(); 
echo "<br />"; 



} 



Come potete notare, questa classe fornisce 
un'implementazione semplice del metodo 
update, ossia si limita a visualizzare un messag- 
gio. Nella realtà questo metodo prowederebbe a 
comunicare il cambiamento all'investitore in 
modo tempestivo, ad esempio tramite un sms. 

La classe astratta Azione, invece, è così imple- 
mentata: 

abstract class Azione 

S 

protected $simbolo; 

protected $prezzo; 

protected $investitori = array(); 

function construct($simbolo, $prezzo) 

{ 

$this->simbolo = $simbolo; 
$this->prezzo = $prezzo; 



{ 


if($investitoreCorrente 
= = $investitore) 


{ 


array_splice($this 


-investitori, $indice, 1); 


break; 


} 


} 


} 




function notify() 


{ 


foreach($this->investitori as 

$investitoreDaAvvertire) 


{ 


$investitoreDaAvvertire->L 


jpdate($this); 


} 


} 


// Getter e Setter 


[-] 


} 



Gli attributi di questa classe sono $simbolo, 
Sprezzo e $investitori. Il primo è una stringa che 
costituisce il simbolo dell'azione (ad esempio 
GOOG per Google). Il secondo, invece, è il prez- 
zo al quale viene scambiata l'azione. L'attributo 
Sinvestitori rappresenta un array di oggetti di tipi 
Ilnvestitore. Gli elementi di quest' array rappre- 
sentano gli osservatori che devono essere notifi- 
cati quando il prezzo dell'azione cambia. A parte 
il costruttore, tale classe espone tre metodi: 

• attach: aggiunge un investitore all' array 

• detatch: rimuove un investitore dall' array 

• notify: invoca il metodo update di ogni investi- 
tore, notificandolo così dell'avvenuto cambia- 
mento del titolo. 

Oltre a questi metodi vi sono i vari "getter" e 
"setter" che non mostriamo per brevità e sem- 
plicità d'implementazione. L'unico metodo che 
vogliamo analizzare è setPrezzo, poiché il cam- 
biamento del prezzo è l'evento che determina 
la notifica dei vari investitori. Ecco il codice di 
setPrezzo: 






ORIGINI 

DEI PATTERN 

Per quanto possa 
sembrare strano, i 
pattern non sono nati 
con l'ingegneria del 
software. Il padre 
universalmente 
riconosciuto dei 
pattern è Christopher 
Alexander, un 
architetto austriaco di 
nascita, ma cresciuto 
in Inghilterra. Anche 
se i suoi lavori 
riguardavano 
l'architettura, 
l'astrazione con cui 
introdusse il concetto 
di pattern fu tale che 
l'idea potè essere 
riutilizzata in vari 
campi, tra i quali 
l'ingegneria del 
software. 



function attach(IInvestitore $investitore) 
{ 



$this->investitori[] 



$investitore; 



function detatch(IInvestitore $investitore) 



{ 



foreach($this->investitori as 
$indice => $investitoreCorrente) 




MIT SUI PARAMETRI 



" 



PHP non è un linguaggio forte- 
mente tipizzato, vale a dire non 
c'è bisogno, come in Java ad 
esempio, di dichiarare il tipo delle 
variabili. Tuttavia, possiamo forni- 
re degli "hint" alle funzioni di 
modo che accettino parametri so- 
lo di un determinato tipo. E' quel- 



lo che abbiamo fatto con il meto- 
do update dell'interfaccia (Investi- 
tore, il quale accetta solo parame- 
tri di tipo Azione. In realtà PHP, in- 
ternamente, esegue un controllo 
tramite l'operatore instanceof. Se 
tale controllo non va a buon fine, 
lo script fallisce. 



http://www.ioprogrammo.it 



Dicembre 2007/ 31 ^ 



028-032:032-035 30-10-2007 17:13 Pagina 32 



ioProgrammo Web T I Design Pattern in PHP 




-e- 



function setPrezzo($prezzo) 



{ 



$this->prezzo = $prezzo; 



$this->notify(); 



} 



Come si può osservare, il metodo è abbastanza 
semplice. Si modifica il prezzo e si notificano 
tutti gli investitori tramite il metodo notify. 
Ogni azione estenderà la classe astratta Azione. 
Ad esempio, la nostra AzioneConcretaFittizia è 
così implementata: 



class AzioneConcretaFittizia 


extends Azione 


{ 




function 


construct($simbolo, $prezzo) 


{ 






parent:: 


construct($simbolo, 

$prezzo); 


} 


} 



Questa classe è così semplice che si limita ad 
invocare il costruttore della classe parent, ossia 
di Azione. 

Un esempio di codice client che utilizza il nostro 
observer pattern è il seguente: 

// Crea gli investitori 

$investitorel = new Investitore("Alessandro 

La cava"); 
$investitore2 = new Investitore("Domentico Morda'"); 
$investitore3 = new Investitore("Antonino 



Catanese"); 



$investitore4 = new Investitore("Francesco 



echo "<br />"; 



// Rimuove un investitore 



$azione->detach($investitore4); 



// Cambia il prezzo 



$azione->setPrezzo(69.00); 

In pratica, il codice appena visto crea quattro 
istanze di oggetti di tipo Investitore. In seguito 
crea un'istanza di AzioneConcretaFittizia e gli 
"attacca" i quattro investitori in precedenza crea- 
ti. Non appena viene invocato il metodo setPrezzo 
sull'azione, il prezzo è modificato e gli observer 
(gli investitori) sono notificati del cambiamento. 
A scopo illustrativo viene poi rimosso un investi- 
tore e richiamato setPrezzo per riscatenare l'even- 
to che causa la notifica degli investitori. L'output 
prodotto è il seguente: 

Notifica per Alessandro Lacava: Il prezzo attuale di 
ACF è 69.96 

Notifica per Domentico Morda': Il prezzo attuale di 
ACF è 69.96 

Notifica per Antonino Catanese: Il prezzo attuale di 
ACF è 69.96 

Notifica per Francesco Passaniti: Il prezzo attuale di 
ACF è 69.96 

Notifica per Alessandro Lacava: Il prezzo attuale di 
ACF è 69 

Notifica per Domentico Morda': Il prezzo attuale di 
ACF è 69 

Notifica per Antonino Catanese: Il prezzo attuale di 

ACF è 69 



Passaniti"); 




// Crea l'azione e registra gli investitori interessati 
$azione = new AzioneConcretaFittizia("ACF", 70.69); 



$azione->attach($investitorel); 



$azione->attach($investitore2); 



$azione->attach($investitore3); 



$azione->attach($investitore4); 



// Ad ogni cambio prezzo vengono notificati gli 

investitori 



$azione->setPrezzo(69.96); 



DICE CLIENT 



Nell'ambito dei design pattern, 
e non solo, si sente spesso 
parlare di "codice client". 
Con tale termine s'intende la 
parte di codice che utilizza il 
pattern. Bisogna fare 
attenzione, quindi, a non 



fraintendere pensando che il 
client sia un browser o qualcosa 
di simile. 

Ad esempio, anche quando si 
usano delle API, il codice che 
accede alle API viene spesso 
detto codice client. 



CONCLUSIONI 

In quest'articolo abbiamo introdotto il concet- 
to di design pattern e ne abbiamo visti alcuni 
implementandoli in PHP. Un design pattern, 
tuttavia, è un concetto astratto. Un pattern può 
essere implementato in PHP5, Java, C# e qual- 
siasi altro linguaggio orientato agli oggetti. La 
loro potenza sta proprio in questo. Essi ci edu- 
cano a progettare e sviluppare software robu- 
sto, flessibile e di qualità, a prescindere dal lin- 
guaggio OOP utilizzato. Ovviamente ciò che 
abbiamo visto deve essere inteso come una 
mera introduzione all'argomento. Lo scopo del 
presente articolo, infatti, era quello di accen- 
dere la lampadina nel lettore che, approfon- 
dendo i vari concetti esposti, potrà dare luce a 
software di qualità, flessibile e più facilmente 
manutenibile. 

Alessandro Lacava 



* 32 /Dicembre 2007 



http://www.ioprogrammo.it 



035-041:032-035 30-10-2007 15:52 Pagina 35 



Un controllo TagCIoud ■ T ioProgrammo Web 



NUVOLE 
ALL'ORIZZONTE 

IL WEB 2.0 HA INTRODOTTO IL CONCETTO DI "TAG CLOUD". IN OGNI BLOG O SITO CHE SI 
RISPETTI ESISTE UNA RAPPRESENTAZIONE GRAFICA DEGLI ARGOMENTI CHE VEDE LE DISCUSSIONI 
PIÙ IN VOGA VISUALIZZATE CON UN FONT PIÙ GRANDE. VEDIAMO COME FARE IN .NET 



-0- 



Una delle caratteristiche apparse con 
l'avvento del Web 2.0, è la possibilità 
che può essere data ai visitatori o ai 
webmaster di un sito di classificare i contenu- 
ti in base a delle etichette o tag. Il fenomeno 
delle comunità Web, e dei siti che permettono 
una condivisione o aggregazione sociale, 
dimostra l'importanza che ha la condivisione 
delle informazioni. La popolarità di siti come 
del.icio.us e di Flickr che permettono il tag- 
ging dei contenuti d'altra parte mostra come 
il meccanismo delle nuvole di tag, o tag cloud 
è stato accolto dal popolo della rete in manie- 
ra molto favorevole. In un Tag Cloud è facile 
vedere, con una rapida occhiata quali argo- 
menti sono più popolari o importanti di altri, 
basta notare quelli con dimensione maggiore. 
Qualsiasi lista di elementi rappresentabili 
sotto forma di testo o parole può usufruire di 
questo modo di rappresentazione. 
L'articolo che vi accingete a leggere mostrerà 
come implementare un server control da uti- 
lizzare in una qualsiasi applicazione ASP.NET, 
sia congiuntamente ad una sorgente dati fisi- 
ca come un database access, ma anche a par- 
tire da una collezione di oggetti business. 



_ ^ del.icio.us /tag/ 






.„. 


,:;:::;:: 


Reputar , 


a -«~ 






















—, 


^zr^r™ 








community computer cookl 


g eoo! CSS culture databas 


n«t audio bandslash blOg btogging blOgS b 

deais design development diy doi 


moad education 






"** envlronmenl TaceDI 


ok fashion tic film mance mefox flash flickr food free freeware fun funny 8 
halloureen hardware health history home IlOWtO humor illustralion 


aiiery games google 

images ìmported 






inspiration interne 


java Javascript jobs 


anguage iearning libraiy llfehacks NnUX mac 


magazine marketing 






mail, media microsoft 


mobile money m™e movies 


m P 3 mUSIC news nyc online ope 


nsource obi photo 






photography phot 


5 phOtOShOp php p«fc asl p 


utics portfoiio productMty programming 


psychclcgy Python radi. 






shopping S i aS h so 


reference research r 
al software tech tect 


ssources remv.s ruby rribyonraiis science search security se» 

nology tips tools toread travel tutorial tutoriais tv 






ubuntu video web 


web2.0 webdesign 


w 8 b.„weddin g » iki Windows . isri , isl wordpress 


■"*"* 





Fig. 1: tag cloud su del.icio.us 



UTILIZZO 

DEL DATABINDIIUG 

Uno dei requisiti che vogliamo soddisfare 
nella progettazione del controllo TagCIoud è 



la possibilità di poterlo legare ad una sorgen- 
te di dati, per esempio ad una tabella di data- 
base, oppure ad un controllo 
ObjectDataSource di oggetti .NET, e così via. 
La classe CompositeDataBoundControl fa al 
caso nostro. Essa viene utilizzata come classe 
da cui derivare un controllo server che deve 
ricavare i dati da rappresentare da una sor- 
gente. Un controllo composito inoltre è un 
controllo che viene costruito mediante com- 
posizione di altri controlli server, standard o 
personalizzato. Essa non viene mai istanziata 
direttamente, ma come faremo noi, la si usa 
come base da cui derivare un nuovo controllo 
DataBound; non mancano nel .NET 
Framwork degli esempi di classi derivate da 
essa molto importanti e praticamente utiliz- 
zati in ogni applicazione web ASP.NET, basti 
citare FormView e GridView. 
Le classi che derivano da CompositeData- 
BoundControl devono fornire il proprio over- 
ride del metodo CreateChildControls, che si 
occupa di creare la gerarchia visuale del con- 
trollo stesso, cioè l'insieme dei controlli figli 
che saranno contenuti nella collezione 
Controls. 

Con un opportuno override di CreateChild- 
Controls verrà creata la nuvola di elementi, 
che dovranno possedere le proprietà che per- 
mettono di dimensionarli in base ad una 
importanza o peso, che permettono di navi- 
gare con un click su ogni elemento, che maga- 
ri possano colorarsi in una gradazione che ne 
riassuma anch'essa l'importanza e quanto 
altro si vuole. 



IL CONTROLLO 
TAGCLOUD 

In questo paragrafo metteremo subito le mani 
in pasta, vedendo come progettare ed imple- 
mentare un controllo server ASP.NET che ci 
permetterà di aggiungere un tag cloud ad un 



.net 



□ CD U WEB 

tagcloud.zip 



& 




M.I.I.UJ-J.UJJIJ.HJja 
f^jl conoscenza di base del 
^ .NET Framework 2.0, e 
di ASP.NET 



*\ Visual Studio 2005, 
jj .NET Runtime 2.0 




http://www.ioprogrammo.it 



Dicembre 2007/ 35 + 



035-041:032-035 30-10-2007 15:52 Pagina 36 



ioProgrammo Web T Un controllo TagCIoud 




-e- 



qualunque sito web, scritto naturalmente 
nella stessa tecnologia. 

Come detto la classe che rappresenta il con- 
trollo deve derivare dalla classe madre di ogni 
controllo data bound, e cioè da 
CompositeDataBoundControl. Un campo pri- 
vato fondamentale della classe sarà natural- 
mente la collezione di elementi che rappre- 
sentano i tag da visualizzare nel controllo 
stesso, in questo caso utilizzeremo una 
Collection di oggetti TagCloudltem, classe 
mostrata subito dopo TagCIoud: 

public class TagCIoud : 
CompositeDataBoundControl 

s 

private Collection<TagCloudItem> nrMtems = new 
Collection <TagCloudItem>(); 

[PersistenceMode(PersistenceMode.InnerProperty), 
MergableProperty(false)] 
public Collection<TagCloudItem> Items 



{ 



get{return nrMtems;} 



Passiamo poi a due campi statici che verranno 
utilizzati rispettivamente per determinare la 
dimensione del carattere del tag, e che quindi 
sarà maggiore per un "peso" maggiore asse- 
gnato al tag stesso, ed un campo per colorare 
il ag in maniera dipendente ancora dal peso, e 
che potete naturalmente personalizzare come 
meglio credete: 



"small", 


"medium", 


"large", 


"x-large", 


"xx-large" 


}; 




static string[] m_colors = 


new string[] 


{ "#E3f555", "#bAb555 
"#777555", "#555555", " 

}; 


', "#999555", 
#333555", "#111555" 



Continuando a parlare di pesi, passiamo al 
metodo NormalizeWeight, che permette di 
normalizzare un peso, e di ottenere l'indice da 
utilizzare per scegliere la dimensione di font 
dall'array m_fontSizes appena visto. La nor- 
malizzazione è necessaria per gestire dei pesi 
che possibilmente possono variare molto in 
magnitudine, e trasformarli in degli indici 
standard. Facciamo un esempio: potrebbero 
esserci dei tag che rappresentano categorie di 
articoli contenenti migliaia di articoli, mentre 
un'altra categoria potrebbe avere un solo arti- 
colo. Piuttosto che cercare di gestire ogni pos- 
sibile grandezza, facciamo in modo che a 
determinare la magnitudine di un tag, sia una 
sorta di differenza "relativa", che normalizzia- 
mo dividendo ogni peso per la differenza fra il 
massimo valore possibile ed il minmo valore 
possibile. La differenza sarà naturalmente un 
valore sempre e comunque minore di 1 e mag- 
giore di 0. Suddividendo l'intervallo [0,1] in 
dei sottointervalli, possiamo ricavarne diffe- 
renti, in questo esempio 7, indici per accedere 
poi alFarray m_fontSizes e m_colors. 



static string[] m_fontSizes = new string[] 
{ "xx-small", 





O lAttributeAccessor 














WebControl gf 

Class 
■* Contrai 
J 




TagCIoud a 

Class 

-+ CompositeDataBoundCo... 

B Fields 

# _color S 
^j> _fontSizes 
$ m_items 

8 Pro p erti es 

]fj* DataColorFidd 

7§* DataHyperlinkFieid 

]fj* DataHyperlinkFor... 

7§* DataTextField 

|?jj* DataTextFormatS... 

7p DataTitl eField 

]fj* DataTitl eFormatS.. 

|Éj* DataWei ghtField 

Tip Items 

[^ TagKey 

ì@ Weights 
Q Methods 

,|* CreateChìIdContr... 

gp CreateltemsFrom... 
* Max 

* Min 

J^ NormalizeWeight 
V Render 




TagCloudltem A 

Class 

B Fields 

J m_href 

$ m_text 

.£ m_title 

*ft m_weight 
B Pro p erti es 

& Href 

ff Text 

]§» Tìtle 

iff Weight 
B Methods 

=-$ TagCloudltem [+... 






l 


i 






BaseDataBoundCo... 's ' 
Abstract Class 
■+ WebControl 






ì 






DataBoundConfml (s 




■+ BaseDataBo 

l 
O INamin 


uno 1 Con trai 

v " 

g Container 








ComposìfeDataBo... % 




1 


Abstract Class 
"frDataBoundControl 

•a 























private static int NormalizeWeight(double weight, 
doublé min, doublé max) 


{ 




doublé 


normal 


= weight/(max-min); 




return 


(normal 


> 0.8) ? 7 










(normal 


> 0.7) ? 6 : 








(normal 


> 0.6) ? 5 : 








(normal 


> 0.45) ? 4 : 








(normal 


> 0.25) ? 3 : 








(normal 


> 0.1) ? 2 : 

1; 


} 



Fig. 2: uml class diagram del controllo TagCIoud 



Ogni tag può avere diverse proprietà, legabili 
ai dati sottostanti, ad esempio ad un databa- 
se, o comunque utilizzabili per personalizzar- 
ne comportamento e aspetto. Per esempio le 
seguenti proprietà permettono di stabilire da 
quale altra proprietà di ogni oggetto della col- 
lezione Items debba essere ricavato il testo da 
utilizzare come collegamento ipertestuale ed 



* 36 /Dicembre 2007 



http://www.ioprogrammo.it 



035-041:032-035 30-10-2007 15:52 Pagina 37 



Un controllo TagCIoud ■ T ioProgrammo Web 



in che formato farlo: 



publiic string DataHyperlinkField 



{ 



get 



{ 



string vai = 
ViewState["DataHyperlinkField"] as string; 



CreateChildControls. In questo caso, per ogni 
tag contenuto nella collezione Items, creata a 
sua volta mediante il metodo 
CreateltemsFromData, viene creato un ele- 
mento HtmlAnchor, vale a dire un classico 
collegamento ipertestuale, sfruttando le pro- 
prietà precedenti per configurarli in maniera 
adeguata, 




-0- 



if (vai != nuli) 



{ 



return vai; 



} 



return String. E mpty; 



set 



{ 



ViewState["DataHyperlinkField"] = value; 
if (this.Initialized) 



{ 



this.RequiresDataBinding = true; 



} 



[Category("Data")] 



public string DataHyperlinkFormatString 



{ 



get 



{ 



string vai = 
ViewState[ "DataHyperlinkFormatString"] 



as string; 



if (vai != nuli) 



{ 



return vai; 



} 



return String. E mpty; 



set 



{ 



ViewState[" DataHyperlinkFormatString"] 



value; 



if (this.Initialized) 



{ 



this.RequiresDataBinding = true; 



} 



In maniera analoga vengono implementate le 
proprietà per determinare il peso, il titolo 
(cioè il tooltip), i dati dei tag. 
Metodo fondamentale di ogni controllo 
Server di ASP.NET, e di cui bisogna creare un 
opportuno override, è il seguente 



protected override int 

CreateChildControls(System.Collections. 

IEnumerable 

dataSource, bool dataBinding) 

i 

if (dataBinding && Ithis.DesignMode) 
CreateltemsFromData(dataSource); 

doublé max = Max(Weights); 

doublé min = Min(Weights); 

int index = 0; 



foreach (TagCIoudltem item in Items) 
{ 



HtmlAnchor a 



new 
HtmIAnchorO; 



a.HRef = 
String. IsNullOrEmpty(item. Href) ? 

this.Page.ClientScript. 

GetPostBackClientHyperlink(thi 

s, index. ToStringO) : 



item. Href; 



a.InnerText = item.Text; 



a.Title = item.Title; 



int normalWeight = 
NormalizeWeight(item.Weight, min, max); 
a.Style.Add(HtmlTextWriterStyle.FontSize, 

m_fontSizes[normalWeight - 1]); 
a.Style.Add(HtmlTextWriterStyle.Color, 

_colors[normalWeight-l]); 



this. Controls. Add(a); 



this. Controls. Add (new 

LiteralControl(" ")); 



index+ + ; 



} 



if (this.DesignMode && Items. 



Count == 0) 



HtmlAnchor a = new 

HtmlAnchor(); 



a.InnerText = "TagCIoud" 



this. Controls. Add(a); 



} 



return Items. Count; 



} 



Il già citato metodo CreateltemsFromData, 
crea, a partire da un oggetto che implementa 
l'interfaccia IEnumerable, la collezione di 





LA CLASSE 

OBJECTDATASO 

URCE 

La classe 

ObjectDataSource è un 
controllo data source 
di ASP.NET che 
rappresenta un 
oggetto con cui 
astrarre dai dati, o da 
utilizzare come 
interfaccia di accesso 
ai dati veri e propri. 
Un controllo 
ObjectDataSource può 
essere utilizzato in 
congiunzione ad un 
controllo grafico data- 
bound per 
visualizzare, 
modificare, cancellare 
dei dati attraverso una 
pagina Web, con poco 
codice o addirittura 
senza scriverne una 
sola riga. 



http://www.ioprogrammo.it 



Dicembre 2007/ 37 + 



035-041:032-035 30-10-2007 15:52 Pagina 3£ 



ioProgrammo Web T Un controllo TagCIoud 



-^> 




O 7 ^B 

BIBLIOGRAFIA 
E SITOGRAFIA 

MSDN Microsoft 

http:/msdn.microsoft.com 

Programming 

Microsoft ASP.NET, 

Dino Esposito, 

Microsoft Press 

Developing Custom 

server Controls, 

msdn2.microsoft.com/en- 

us/library/zt27tfhy.aspx 



elementi da rappresentare come rag. 

private void 

CreateItemsFromData(System.Collections. 
IEnumerable dataSource) 

i 

foreach (object data in dataSource) 

{ 

TagCIoudltem item = new 

TagCIoudltemO; 
if 
(String.IsNullOrEmpty(this.DataHyperlinkField)) 

{ 

if 
(String.IsNullOrEmpty(this. Data Hy peri in kFormat 

String)) 
item. Href = 
String. Empty; 
else 
String. Format(CultureInfo.CurrentCultu re, 
this.DataHyperlinkFormatString, new object[] { 

data 

}); 



else 



{ 



item. Href = DataBinder.Eval(data, 



this.DataHyperlinkField, 



this.DataHyperlinkFormatString); 



} 



if 
(!String.IsNullOrEmpty(this.DataTextField)) 



{ 



item.Text = 
Data Binder.Eval (data, 



this.DataTextField, 



this.DataTextFormatString); 



} 



if 
(!String.IsNullOrEmpty(this.DataTitleField)) 



{ 



item.Title = 
Data Binder.Eval (data, 



this.DataTitleField, 



this.DataTitleFormatString); 



} 



if 
(!String.IsNullOrEmpty(this.DataWeightField)) 



{ 



item.Weight = 
Convert.ToDouble(DataBinder. 



GetPropertyValue(data, 



this.DataWeightField)); 



} 



this.Items.Add(item); 



GLI ELEMENTI 
DELLA NUVOLA 

Ogni tag del controllo TagCloudControl è rap- 
presentato da un'istanza della classe 
TagCIoudltem, molto semplice nella sua 
struttura, e facilmente personalizzabile in 
base alle esigenze ed a queli dati si vogliano 
rapresentare ed utilizzare: 



public class TagCIoudltem 


{ 


private string m_text; 


private string m_title; 


private doublé m_weight; 


private string m_href; 


public TagCIoi 


dltemQ 


{ 


} 


public TagCloudItem(string text, doublé 

weight) 


{ 


this.m_text = text; 


this.m_weight = weight; 


} 


public TagCloudItem(string text, doublé 
weight, string href) 


: this(text, weight) 


{ 


this.m_href = href; 


} 


public TagCloudItem(string text, doublé 
weight, string href, string title) 


: this(text, weight, href) 


{ 


this.m_title = title; 


} 


public string Text 


{ 


get 


{ 


return m_text; 


} 


set 


{ 


m_text = value; 


} 


} 




public string Href 


{ 


get 


{ 


return m_href; 


} 



* 38 /Dicembre 2007 



http://www.ioprogrammo.it 



035-041:032-035 30-10-2007 15:52 Pagina 39 



Un controllo TagCIoud ■ T MULTIMEDIA 



-0- 



set 


{ 


m_href = value; 


} 


} 




public string Title 


{ 


get 


{ 


return m_title; 


} 


set { m_title = value; } 


} 




public doublé Weight 


{ 


get { return m_weight; } 


set { m_weight = value; } 


} 


} 



UTILIZZARE 
IL CONTROLLO 

Il controllo così implementato è pronto ad 
essere utilizzato in una pagina ASP.NET. Basta 
avere una sorgente dati da usare per generare 
i tag del controllo. In questo primo esempio, 
sia per semplicità, ma anche per mostrare una 
diversa possibilità, sarà direttamente costrui- 
ta la collection Items: 



<dcweb:TagCloud ID = 


"tagCIoudl" runat="server"> 


<Items> 


<dcweb:TagCloudItem 

Text="Iteml" 


Href="Test" 
Title= "Default. aspx?tag = Itemi" Weight="4"/> 


<dcweb:TagCloudItem 

Text="Item2" 


Href="Test" 


Title="Default.aspx?tag = Item2" Weight="4" /> 


</Items> 


</dcweb:TagCloud> 



Una possibilità più avanzata è quella di utiliz- 
zare un controllo ObjectDataSource. 
Costruendo per esempio una classe da utliz- 
zare come sorgente dati ed una per rappre- 
sentare i tag, nella seguente maniera: 



public Tagltem(string name, int 
weight) 



{ 



this.m_name = name; 



this.m_weight 



weight; 



} 



public string Name 



{ 



get { return m_name; 



} 



} 



public int Weight 



{ 



get { return 



m_weight; 
} 



public override bool Equals(object obj) 



{ 



Tagltem other = obj as Tagltem; 



if (other == nuli) 



return false; 



return this.Name == other.Name; 



} 



public class TagltemsSource 



{ 



public TagltemsSourceQ 



{ 



} 



public Tagltem[] Getltems() 



{ 



return new Tagltem[]{ 



new TagItem(".NET 

",30) 



new TagItem("C# 

",218) 



new TagItem("VB ",21) 



new TagItem("HTML 
",4) 



new TagItem("Java 

",69) 



new 
TagItem("JavaScript ",234) 



new TagItem("Perl ",6) 



new TagItem("PHP ",40) 



new TagItem("Ruby 
",37) 




public class Tagltem 


{ 


private int m_weight; 




private string m_ 


.name; 



Basterà a questo punto configurare 
TObjectDataSource come segue, all'interno 
del codice HTML della pagina: 



http://www.ioprogrammo.it 



Dicembre 2007/ 39 ^ 



035-041:032-035 30-10-2007 15:53 Pagina 40 



ioProgrammo Web T Un controllo TagCIoud 



-e- 





Antonio Pelleriti, 

ingegnere informatico, 

sviluppa software da 

più di dieci anni e si 

occupa di .NET sin 

dalla prima versione 

Beta. È chief software 

architect di 

DynamiCode s.r.l.. 

Software Factory in cui 

progetta e swiluppa 

soluzioni custom ed in 

outsourcing 

(www.dynamicode.it). 

Può essere contattato 

per suggerimenti, 

critiche o chiarimenti 

all'indirizzo e-mail 

antonio.pelleriti@dotneta 

rchitects.it 



Articoli 
% ID 

IDCategoria 
Titolo 



Catego 



1 ID 
Categoria 



Categorie. ID)"> 



Fig. 3: le tabelle del database 



<asp:ObjectDataSource ID = "ItemsSource" 

runat= "server" SelectMethod = "GetItems" 
TypeName="ItemsSource" /> 

Al controllo TagCIoud basterà indicare la sor- 
gente di dati mediante la proprietà 
DataSourcelD. 

Le varie proprietà DataTextField, 
DataTitleField, e così via, verranno fatte corri- 
spondere alle proprietà degli oggetti Tagltem 
utilizzati come elementi da rappresentare nel 
controllo stesso: 

<dcweb:TagCloud ID="tagCloudl" runat="server" 

DataSourceID = "ItemsSource" 

DataTextField = "Categoria" 

DataTitleField = "Categoria" 

DataTitleFormatString = "{0} articoli" 

DataWeightField = "Tag"> 



IL DATABASE 

Per mostrare come ricavare i dati da un data- 
base realizzeremo una tabella Articoli ed una 
tabella Categorie, utilizzando Access per sem- 
plicità. 

Le due tabelle sono correlate come mostrato 
in figura, vale a dire ogni articolo appartiene 
ad una ed una sola categoria. Contando poi 
quanti articoli fanno parte di una certa cate- 
goria, si utilizzerà il nome della categoria stes- 
sa come Tag, ed il numero di articoli di una 
data categoria come peso del tag stesso. 
Aggiungendo alla pagina un controllo Access- 
DataSource, per ricavare tutti gli articoli pre- 
senti in archivio, basta una query come la 
seguente, mostrata all'interno della proprietà 
SelectCommand del controllo inserito all'in- 
terno della pagina aspx: 

<asp:AccessDataSource ID="AccessDataSourcel" 
runat= "server" DataFile="~/App_Data/items.mdb" 
SelectCommand = "SELECT Articoli. ID, 

Articoli. IdCategoria, Articoli. Titolo, 

Categorie. Categoria FROM (Articoli INNER JOIN 

Categorie ON Articoli. IdCategoria = 



</asp:AccessDataSource> 

adesso, utilizzando il metodo Select di 
AccessDataSource, al caricamento della pagi- 
na, si può ricavare la collezione di Tagltem da 
utilizzare impostando la proprietà 
DataSource del controllo TagCIoud. Il metodo 
Select esegue la query presente nella pro- 
prietà SelectCommand e restituisce un ogget- 
to che implementa l'interfaccia Ienumerable. 
Gli elementi di tale oggetto si possono scorre- 
re mediante il metodo MoveNext. Ogni ele- 
mento è un oggetto DataRowView, che possie- 
de tante colonne quante sono quelle indicate 
nella query: 



IEnumerable results= 

AccessDataSourcel.Select(new 
DataSourceSelectArgumentsO); 


List<TagItem> items = new List<TagItem>(); 


IEnumerator enumerator= 


results.GetEnumerator(); 


Tagltem item; 


DataRow row; 


int index; 


while(enumerator.Movel\lext()) 


{ 


row=(enumerator.Current as 

DataRowView). Row; 


item = new 
TagItem(row["Categoria"].ToString(),l); 




if (items. Contains(item)) 


{ 


index= items. IndexOf (item); 


item = new 
Tagltem (items[index].Name,items[index]. 


Weight+1); 


items. RemoveAt( index); 


items. Add(item); 


} 


else items. Add(item); 


} 


tagCIoudl. Items. Clear(); 


tagCIoudl. DataTextField = "Name"; 


tagCIoudl. DataTitleField = "Weight"; 


tagCIoudl. DataTitleFormatString = "{0} articoli 

sull'argomento"; 


tagCIoudl. DataWeightField = "Weight"; 


tagCIoudl. DataHyperlinkField = "Name"; 


tagCIoudl. Data Hy peri in kFormatString = 

"Default. aspx?tag = {0}"; 


tagCIoudl. DataSource = items; 



per ogni elemento, vale a dire per ogni artico- 
lo, viene letta la categoria, ed incrementato il 
numero, cioè il peso, del tag. Se un item con 




+ 40 /Dicembre 2007 



http://www.ioprogrammo.it 



035-041:032-035 30-10-2007 15:53 Pagina 41 



Un controllo TagCIoud ■ T ioProgrammo Web 



una certa categoria non esiste ancora, esso 
viene rimosso dalla Lista e reinserito dopo 
averne incrementato di uno la quantità. 
Alla fine del ciclo che legge tutta l'enumera- 
zione di articoli trovati, vengono impostate le 
proprietà del controllo TagCIoud, mostrando 
come testo di ogni Tag la proprietà Name del 
Tagltem, che in questo caso sarà il nome della 
categoria, mentre come titolo viene ancora 
una volta mostrato il testo "{0} articoli sull'ar- 
gomento", sostituendo al parametro {0}: il 
numero di articoli presenti nella categoria. 
La figura seguente mostra il risultato 



CONCLUSIONI 

Nell'articolo si è visto come implementare un 
server control di ASP.NET per realizzare For- 
mai onnipresente funzionalità dei Tag Cloud, 
le nuvole di Tag che permettono di riassume- 
re e visualizzare visivamente, gli argomenti 
più popolari di un sito web o di un blog. Dopo 
aver realizzato il controllo abbiamo visto 
come utilizzarlo all'interno di un normale 
progetto web, utilizzando come sorgente dati 



sia un Object Data Source, quindi una colle- 
zione di oggetti .NET, sia un database access 
dal quale leggere i dati con cui costruire gli 
oggetti da rappresentare nel controllo. Si 
potrebbero effettuare ancora alcune migliorie 
ad esempio progettando un backend per la 
gestione manuale dei pesi e 
Timmissione/rimozione di argomenti. Ma 
questo lo lasciamo alla vostra fantasia... 

Antonio Pelleriti 




^ Tag Cloud Test - Windows Internet Explorer 


| D |0 \m-è3^ 




(3É5 T 8L http://localho&t:43C ▼ +t X 1 Google 


p - 


A * J0 Tag Cloud Test Si - - # 


1— fc » 
^ \ijf Pagina ^ 


^ .NETVisual 

Basic java Fortran Ruby C# php 


i 



Fig. 4: il nostro tagcloud in funzione 




042-045:072-080 30-10-2007 15:55 Pagina 42 



SISTEMA T I Estendere Internet Explorer 



CREARE ADDON PER 
INTERNET EXPLORER 

MOLTI PENSANO CHE LO SVILUPPO DI ADD-ON PER IE SIA RISERVATO A PROGRAMMATORI 
C++ , VEDIAMO COME È INVECE POSSIBILE AGGIUNGERE NUOVE FUNZIONALITÀ AL BROW- 
SER SEMPLICEMENTE ATTRAVERSO DEI SEMPLICI SCRIPT 



^ 




Lj CD Lj WEB 

IEADD0HS.zip 



^ 



SjjSmmmmm 



n 




REQUISITI 



i«.M.wmui.m,« 

f^T\ Javascript e DONI, 
j^f) Registry di Windows 



aa^j. 



Tempo di realizzazione 



rvì 



Lo sviluppo di funzionalità aggiuntive per i 
browser Web trova indubbiamente in Fi- 
refox la piattaforma più "amichevole" per 
il programmatore: con un po' di XML e di Javascript 
è possibile ottenere dei risultati veramente notevoli 
(basti pensare a "Firebug" che è ormai diventa- 
to un must per il debugging per gli sviluppatori 
web). In Internet Explorer le cose non sono, a 
prima vista, così facili. Analizzando la docu- 
mentazione in merito ci si imbatte infatti in del- 
le API di basso livello, quasi esclusivamente ri- 
servate a programmatori C++ (anche se, come 
vedremo in un prossimo articolo, è possibile uti- 
lizzare anche il .NET Framework). In definitiva 
quindi sembrerebbe che lo sviluppo di funzio- 
nalità aggiuntive per IE sia un lavoro che richie- 
de un impegno non certamente "amatoriale". 
Tuttavia questo assunto non è del tutto vero. In 
realtà quello che non tutti sanno è che anche sol- 
tanto utilizzando Javascript è possibile svilup- 
pare degli add-onperlE. 
In particolare vedremo come sviluppare, attraverso 
gli script, nuovi comandi per il menu principale 
ed il menu contestuale di IE. 



UN PO 1 DI TEORIA 

Per programmare un add-on attraverso uno script 
c'è ben poca teoria da conoscere, tuttavia è co- 
munque necessaria qualche nozione di base. 
Per prima cosa bisogna sapere che la configura- 
zione di un nuovo add-on è tutta contenuta nel re- 
gistro di configurazione di Windows. 
Occorre andare alla chiave del registro di configu- 
razione 

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ 

Internet Explorer\Extensions 

All'interno della chiave creare una sotto-chiave 
che ha per nome una stringa GUID che identifica 
in modo univoco il nostro Add-On. 
Sotto quest'ultima chiave è necessario creare: 



• Un nuovo valore String di nome CLSID con 
valore {lFBA04EE-3024-lld2-8FlF-0000F87 
ABD16} (che indica che si tratta di una voce 
di menu) . 

• Un nuovo valore String di nome MenuText che 
sarà il testo della voce. 

• Un nuovo valore Stringai nome Script che con- 
terrà il percorso assoluto dello script 

Una cosa importante da ricordare è che il file 
contenente lo script deve avere estensione .htm 
(non .js come potrebbe apparire più logico) si 
tratta praticamente di un file HTML senza in- 
terfaccia, che contiene solo il tag <script>, ad 
esempio: 



<script language="javascript" 



type= "text/javascript" > 



/* ... codice */ 



</script> 



CONFIGURAZIONE 
DI URIA MUOVA VOCE 

L'aggiunta di una nuova voce al menu contestua- 
le è più o meno simile. Si tratta qui di agire sulla 



I--C3 AboutURLs 

•t _J i I i Siili 

♦ _J Advar,edOpticn 5 

! | I ! f I 1 

g-Q AutoComplete 

ult Behaviors 
+ _| Default HTML Editor 
+ _J Default MHTML Editor 

S-S EmbedExtnToCIsidMappings 
g-fil Explorer Bars 

on Compatibility 
g.» Extersions 

_J ìC8BOE5COHFCB-i!CF-AAA5-OU401C60850U 

^ — BB 

_l - '"I" - - - «- : -'•!■.. .lLJ. A-, 
_| {2EAF5BB1-C70F-11D3 

_J {2EAF5BB2--LI7UF- 1 fai i , ,~ 

_J {48FFE3FF- 36M-44fcd-A; CO ÌD34414EAC0D*! 

_j ':r-=pr-- !,=,.:■" ,[■" c '' ,c f v-.:--' -:■ y, 

_J Ic95re06i - aau03cl57a) 

_J • ,1 = n = 

_j [-- c !-mhi-i<i i i- r im i- -i.- 

2~J I eed Distovery 
\ | [mage Caching 

_| il» .' .i.an.Tlai'J ì .1 :nPt .,!.:. 



REG_5Z (vali 

REG_SZ 4.1FE 

REG_SZ My Add-On 

REG_5Z C:\Progi 



H r- F Hit E III \ V e F F L r+ h F 



Figura 1: configurazione di un nuovo Add-On nel registry 
di Windows 



* 42 /Dicembre 2007 



http://www.ioprogrammo.it 



042-045:072-080 30-10-2007 15:55 Pagina 43 



Estendere Internet Explorer ■ T SISTEMA 



-e- 



chiave di registro: 

HKEY_CURRENT_USER\Software\Microsoft\Internet 

Explorer\MenuExt 

Qui creeremo una nuova sotto- chiave il cui nome 
rappresenterà il testo della voce di menu, ad esempio: 

HKEY_CURRENT_USER\Software\Microsoft\Internet 

Explorer\MenuExt\Mio Menu 

Nel valore di default della chiave inseriremo il per- 
corso assoluto dello script 

Opzionalmente potremo inserire nella nuova chia- 
ve un valore DWORD chiamato Contexts che de- 
termina in quali situazioni far comparire la voce 
nel menu contestuale il valore potrà essere uno di 
questi (combinabili anche con OR logico): 



Contesto 


Valore ^ 


Default 


Oxl 


Immagini 


0x2 


Controlli 


0x4 


Tabelle 


0x8 


Selezione di testo 


0x10 


Link 


0x20 





Se poi vogliamo che il file HTML contenente lo 
script si apra in una nuova finestra di dialogo mo- 
dale (come se fosse stato richiamato con show- 
ModalDialog) occorre creare il valore DWORD dal 
nome Flags impostato ad 1. 



REALIZZARE URI PRIMO 
ADD-ON PER IL MENU 
CONTESTUALE 

Come abbiamo visto la configurazione di nuove vo- 
ci di menu è abbastanza semplice, vediamo quindi di 
creare il nostro primo Add-On utilizzando gli script. 
Il nostro Add-On sarà qualcosa di più del classico 
"Hello World" : si attiverà sul menu contestuale e, in 
una finestra di dialogo, visualizzerà il codice HTML 
corrispondente alla selezione sulla pagina. 
Il codice sarà tutto contenuto in un semplice file 
HTML (ShowSource.htm) che contiene un ele- 
mento <PRE> ed uno script. 
Lo script avrà il compito di : 

• trovare la selezione corrente della pagina, 

• estrarne il codice HTML, 

• trasformare i tag < e > nelle entità HTML 8dt } e &g£ 



(altrimenti non si vedrebbe il codice, ma l'output) 

• Inserire il tutto nell'elemento <PRE>. 

Nello scrivere il codice ci troviamo di fronte ad una 
prima difficoltà : se il codice viene eseguito in una 
finestra di dialogo, quindi diversa dalla pagina del 
browser, mentre lo script si riferisce ad oggetti pre- 
senti nell'altra pagina, come fare ad ottenere il ri- 
ferimento all'oggetto window della pagina princi- 
pale? 

Per fortuna il problema è facilmente risolvibile, la 
finestra principale è infatti referenziata dalla pro- 
prietà menuArguments dell'oggetto external della 
finestra corrente. 
Il codice quindi, alla fine, si presenta così: 

<html> 
<head> 

<title>Selection Source</title> 

<link rel = "STYLESHEET" type="text/css" 

href="star-light.css"> 
</head> 
<body> 

<pre id = "htmlContainer" class="html"> 

</pre> 

<script language="javascript" 

type="text/javascript"> 

_r 

riferimento a finestra principale 

V_ 

var win = 

external. menuArguments; 

var doc = win.document; 

_r 

Selezione corrente 

V_ 

var sei = doc.selection; 

var mg = sel.createRange(); 

var src = rng.htmIText; 



Se la selezione corrente non esiste prende tutto il 

codice del BODY 

V_ 

if (src.length <= 0) src = 

doc.body.outerHTML; 
src = 
src.replace(/</g,'<').replace(/>/g,'><br/>') 
htmlContainer.innerHTML=src 

</script> 
</body> 
</html> 

In questo caso, per la formattazione del codice 
HTML della finestra abbiamo utilizzato un fo- 
glio di stile esterno; il nostro script può infatti 
fare riferimento a CSS e SCRIPT esterni che ri- 




COS'È 
URI GUID 

Il GUID (Globally 
Unique Identifier, 
identificatore unico 
globale) è un numero 
utilizzato per 
identificare in 
maniera univoca un 
componente 
software. Anche se il 
GUID non è 
sicuramente univoco 
il numero possibile 
di combinazioni 
(2128) è talmente 
elevato da evitare 
una coincidenza di 
due codici in un 
sistema. 

Nel sistema Windows 
il GUID viene 
utilizzato soprattutto 
nel Registro di 
Configurazione 
(Registry) di sistema. 
Maggiori 
informazioni 
possono essere 
reperite su 
http://it.wikipedia.org/ 
wiki/GUID 



http://www.ioprogrammo.it 



Dicembre 2007/ 43 + 



042-045:072-080 30-10-2007 15:55 Pagina 44 



SISTEMA T I Estendere Internet Explorer 




siedano nella stessa posizione (o in cartelle interne) 
del file stesso. 

A differenza delle voci del menu principale, che 
non hanno finestre di dialogo, le voci di menu con- 
testuali possono attivare finestre di dialogo, quin- 
di nel file HTML che andremo a predisporre il 
markup è relativo a quest'ultime. 



CONFIGURAZIONE 

Una volta creato il nostro file HTML occorre con- 
figurarlo nel Registry di Windows. 
Per prima cosa dovremo creare una chiave nella 
posizione : 

HKEY_CURRENT_USER\Software\Microsoft\Internet 

Explorer\MenuExt 



Welcome to Wikipedia, 

b can edit. 
2,052,770 articles in English 



tions-Help 




Figura 2: voce nel menu contestuale di IE 



-0- 



Attenzione perché il nome della chiave sarà quel- 
lo che apparirà come voce del menu contestuale. 
Nel nostro caso il nome sarà Show Source, quindi 
creeremo la chiave : 

HKEY_CURRENT_USER\Software\Microsoft\Internet 

Explorer\MenuExt\Show Source 

Come valore di default (Predefinito) della chia- 
ve assegniamo la path completa del file di codi- 
ce che abbiamo editato (nel nostro caso sarà 
C:\Programmi\IEADDONS\Test\ShowSource. htm) . 
Adesso, poiché vogliamo che il nostro Add-on 
apra una finestra di dialogo, creiamo un valore di 
tipo DWORD chiamato Flags e gli assegniamo il 
valore 1 . 



TEST E DEBUG 

Avviamo IE, o chiudiamolo e riavviamolo se fosse 
stato già aperto. 

Andiamo a selezionare una porzione di pagina (te- 
sto, immagini ecc..) e, attivando il menu conte- 
stuale con il tasto destro, vedremo comparire la 
nuova voce Show Source (figura 2) . 
Cliccando sulla voce quindi verrà eseguito il no- 
stro Add-on in una nuova finestra di dialogo come 
quella visibile in figura 3. Per il debug invece la co- 
sa interessante da sapere è che ogni volta che cam- 
biamo qualcosa nel file di codice non è necessa- 
rio riawiare Internet Explorer. 



particolarmente per azioni da applicare alla sin- 
gola selezione, quelli al menu principale invece 
sono più indicati per azioni relative all'intera pa- 
gina. 

Passiamo quindi a creare un Add-On per il me- 
nu principale che ha la semplice funzione di ri- 
velare la struttura del documento corrente con- 
tornando le tabelle di blu, le celle di rosa e i DIV 
di verde (cosa che può essere utile allo svilup- 
patore per comprendere il layout della pagina). 



IL CODICE 

Anche qui creiamo un nuovo file HTML, che chia- 
meremo ShowStructure.htm, che però contiene 
solo il tag <script> (ogni altro markup sarebbe in- 
fatti inutile visto che l'Add-On non viene visualiz- 
zato in una finestra ma si applica direttamente al- 
la pagina). Il codice anche qui è semplice: 

• si ottiene il riferimento alla pagina attraverso exter- 
nalmenuArguments e, da questa, al documento 

• si crea una semplice funzione che imposta il bor- 
do di un elemento con un dato colore 

• si ottengono gli elementi corrispondenti ai Tag che 
vogliamo contornare 

• si applica la funzione agli insiemi di elementi in 
precedenza ricavati 

Tutto il codice contenuto in ShowStructure.htm 
sarà quindi: 



UN PRIMO 
ADD-ON PER IL MENU 
PRINCIPALE 

Gli Add-On del menu contestuale si prestano 



<script language= 


= "Javascript" 


type="text/javascript"> 


/* 


Oggetto window della pagina corrente 


*/ 


var parentwin = 


externa 1. menu Arguments; 




/* 



* 44 /Dicembre 2007 



http://www.ioprogrammo.it 



042-045:072-080 30-10-2007 15:55 Pagina 45 



Estendere Internet Explorer ■ T SISTEMA 



Oggetto document della pagina corrente 

V_ 

var doc = parentwin. document; 

_r 

Funzione per applicare bordi colorati 

V_ 

function applyBorder(elements,color){ 

for(var i=0;i<elements.length;i++){ 
var node = elements[i]; 



node.style.border = 



"lpx solid " + 

color; 



• Poi creiamo un altro valore STRING che chia- 
miamo MenuText , questo valore contiene il te- 
sto della voce di menu, nel nostro caso sarà "Show 
Structure". 

• Infine creiamo un ulteriore valore STRING chia- 
mato Script che contiene la path completa del 
file di codice che abbiamo editato (nel nostro 
caso sarà C:\Programmi\IEADDONS\Test\Show- 
Structure.htm). 




/* 



-e- 



Insiemi di elementi 



*/ 



var tables = doc.getElementsByTagName("TABLE"); 
var cells = doc.getElementsByTagName("TD"); 
var divs = doc.getElementsByTagl\lame("DIV"); 

/* 



Applicazione della funzione 



*/ 



applyBorder(tables,"#3300ff"); 



applyBorder(cells,"#ff0099"); 



applyBorder(divs,"#33ff00"); 



</script> 



CONFIGURAZIONE 

La configurazione dell'Add-On è leggermente di- 
versa rispetto a quella vista per il menu contestuale. 
Per prima cosa dovremo scegliere una GUID (Glo- 
bally Unique Identifier) che identifichi in modo 
univoco il nostro Add-on, per farlo se abbiamo Vi- 
sual Studio possiamo usare il generatore che troviamo 
tra gli strumenti, guidgen.exe, altrimenti possia- 
mo usare uno dei tanti tool online (uno di essi è 
anche nel mio sito all'indirizzo www.smelzo.it/guid - 
gen). 
Quindi dovremo creare una chiave nella posizione : 

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ 

Internet Explorer\Extensions 

Utilizzando come nome la GUID prescelta, ad esem- 
pio: 

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ 
Internet Explorer\Extensions\{lDC792EA-F5DA-47c2- 

BFED-FB543788F8F2} 

All'interno della chiave creiamo: 

• Un valore STRING chiamato CLSID, questo va- 
lore deve corrispondere a {lFBA04EE-3024-lld2- 
8F1F-0000F87ABD16} (che indica che si tratta di 
un'estensione al menu principale). 



Terminata la configurazione chiudiamo IE se era 
in esecuzione e riavviamolo e apriamo una pagina 
qualsiasi. 

A questo punto se andiamo nel menu principale 
alla voce Strumenti/ Tools noteremo che è com- 
parsa una nuova voce, Show Structure appunto. 
Attivando questa voce notiamo che lo script viene 
eseguito ed il layout viene evidenziato. 



CONCLUSIONI 

In questo articolo abbiamo visto il modo più sem- 
plice di personalizzare IE, ovvero mediante l'uti- 
lizzo di semplici script Javascript. 
Anche se l'utilizzo delle API consente cose ovviamente 
di fare cose più complesse, attraverso questa tec- 
nica comunque si possono costruire degli Add-On 
non banali con un impegno di tempo ragionevole. 

Francesco Smelzo 



I Collegamenti ^ ITI5 Galileo Calili Pop-up Blocker 
Phishing Filter 



rniiini iy mier 

W Mah Page -Wlklpe M ~ anage Add-ons 



▼ |\V http ://en, wild: ki/Main_Page 



File Edit View Favorites Tools Help 
Google |lGhBD16 ^J Cerca Delete Browsing History. . 



► -ship j^ 




Yo. — 

5ubscribe to this Feed.. 

Feed Discovery 

Windows Update 



WlKIPEDlA 

The Free Encycfapedid 

navigati ori 



Main page 
Contents 
Featured content 
Currentevents 



AboutWii 
Community portai 
Recent changes 
Contact Wikipedia 



^ ;ource | 



Diagnostica problemi di connessione., 
Mostra collegamenti correlati 
Crea preferito portatile. . , 
Invia a OneNote 



Structure 
SUI I JdVd CUI ibUlb 



Internet Options 




ia, 

i edit. 



Barnard's Star is a very low 
American astronomer E. E. E 
arcseconds per year, which t 
relative to the Sun. Lying at £ 
Barnard's Star is the nearest 
system to the Sun, and the f 
components of the Alpha Centauri system. Desf 
visitile with the unaided eye. It is a relatively we 



DOCUMENTA- 
ZIONE 

La documentazione 
sulle estensioni di IE 
mediante Script non 
è particolarmente 
abbondante, 
qualcosa può essere 
comunque reperito 
all'indirizzo 
http://msdn2.microsoft. 
com/en-us/library/ 
aa753616.aspx. 



Figura 3: nuova voce nel menu principale di IE 



http://www.ioprogrammo.it 



Dicembre 2007/ 45 y 



046-052:072-080 30-10-2007 15:57 Pagina 46 



SISTEMA T ■ Programmare con JMATTER 



JMATTER SEMPLIFICA 
LO SVILUPPO IN JAVA 

LE APPLICAZIONI SOFTWARE SPESSO COMPRENDONO UN SET DI FUNZIONALITÀ MOLTO 
SIMILI; PERCHÈ IMPLEMENTARLE OGNI VOLTA DA ZERO? OGGI TUTTO CIÒ SI PUÒ EVITARE 
E JMATTER TI DA UNA MANO A FARE TUTTO PIÙ VELOCEMENTE 



-0- 




Ci cd Ci web 

JMATTER.zip 



jn 




REQUISITI 



' Java,Ant 



JDK 1.5, Ant, Edipse 
3.x 



Tempo di realizzazione 



Vu-J *%* ** 



LJ ingegneria del software negli ultimi anni 
ha assistito al consolidamento di tecniche 
I e metodologie di sviluppo che hanno faci- 
litato sotto tutti gli aspetti i progetti di piccole, me- 
die e grandi dimensioni. Il mondo degli sviluppa- 
tori non si è fatto mancare proprio nulla; gli ap- 
procci così detti "Agili" hanno rimpiazzato le tec- 
niche classiche di sviluppo, altrettanto numerose 
sono state le novità che hanno scosso il nostro 
mondo. 

Nonostante tutti questi miglioramenti è impossibi- 
le negare che molti dettagli implementativi riguar- 
dano aspetti ripetitivi della programmazione stessa. 
Immaginiamo il caso di un'applicazione desktop, a pre- 
scindere dal dominio applicativo, il progettista prima 
e il programmatore dopo dovranno sempre prende- 
re delle decisioni che non dipendono (o meglio non 
dovrebbero dipendere) dal dal problema in sé stesso. 
Come strutturare l'interfaccia grafica? Usare un ORM 
per il mapping dei dati oppure limitarsi all'utilizzo 
di JDBC? ORM sì, ma quale? Una volta prese queste 
decisioni, si presentano altri processi decisionali an- 
cora non dipendenti dal contesto. In quale directory 
mettere le immagini che compaiono sull'interfaccia 
grafica? Oltre a queste decisioni, anche alcune fun- 
zionalità di base dovranno per forza essere imple- 
mentate; si pensi all'autenticazione degli utenti e ai 
ruoli da assegnare loro. 

Tali decisioni, tali funzionalità ed i conseguenti 
dettagli implementativi incidono sui tempi di rea- 



r INSTALLARE JMATTER 



L'utilizzo di JMatter prevede dei 
requisiti software dei quali deve 
essere fornito il nostro enviroment 
di sviluppo; in particolare è 
prevista la presenza di un JDK 1.5 
e di Ant. Acquisiti questi requisiti, 
bisogna scaricare dall'uri 
www.jmatter.org/pages/download il 
framework in formato .zip. 
Supponiamo di scompattare il 
tutto sotto "C:\", avremo una 



directory C:\jamtter-<dataRealese> 
sotto la quale possiamo trovare 
tutto ciò che ci serve. Infatti 
possiamo notare la presenza di tre 
directory: jma tter, modules e 
demo-apps. La prima contiene le 
librerie pricipali su cui si basa il 
framework, la seconda le librerie 
di supporto mentre nella terza ci 
sono esempi completi e 
funzionanti. 



lizzazione in modo drammaticamente pesante. A 
volte si arriva a soglie che toccano il 90%. In questo 
articolo studieremo e prenderemo in esame un fra- 
mework che ci facilita nella realizzazione di appli- 
cazioni desktop, il suo utilizzo è così proficuo che 
consente di concentrare i nostri sforzi quasi esclu- 
sivamente sul dominio di business dell'applica- 
zione stessa senza occuparci dello strato "fisico" 
che risiede sotto la logica implementativa. In pra- 
tica JMatter fornirà la struttura software sulla qua- 
le applicare la logica di business del progetto. A 
prescindere dal contesto avremo a disposizione 
un'interfaccia grafica ben strutturata e definita. Sa- 
premo già in quale directory posizionare le im- 
magini dei pulsanti, anche il nome da dare a tali 
immagini sarà già stabilito dal framework. Questi 
sono solo piccoli esempi delle facility studiate e 
messe a disposizione da JMatter. Tra poco potre- 
mo goderne i benefici attraverso una vera e pro- 
pria full-immersion grazie alla quale andremo a 
sviluppare un'applicazione discretamente com- 
plessa. 



PRONTI, VIA! 

Come spesso accade in questa rivista il modo mi- 
gliore per imparare l'utilizzo di un framework di 
sviluppo è quello di vederlo all'opera in un pro- 
getto concreto. L'obiettivo di questo progetto è 
quello di realizzare la "gestione delle letture", una 
sorta di schedario delle nostre fonti di informa- 
zione. Ovviamente la nostra applicazione preve- 
de una fase di login che devono effettuare sia gli 
utenti semplici sia il cosiddetto amministratore. 
Per meglio percepire le peculiarità degli strumen- 
ti messi a disposizione da questo framework pro- 
cederemo in modo incrementale, ovvero aggiun- 
geremo funzionalità poco per volta evidenzian- 
done i dettagli implementativi. Per prima cosa dob- 
biamo costruire l'infrastruttura iniziale del pro- 
getto; per fare ciò spostiamoci sotto C:\jmatter- 
<dataRealese>\jmattere digitiamo il seguente co- 
mando: 



* 46 /Dicembre 2007 



http://www.ioprogrammo.it 



046-052:072-080 30-10-2007 15:57 Pagina 47 



Programmare con JMATTER ■ T SISTEMA 



ant new-project-ui 



-0- 




Figura 1: La form per la creazione di nuovi progetti. 



Così facendo apparirà una un piccolo form come 
riprodotto in figl. 

Bisogna inserire il nome del progetto (il nostro lo 
chiameremo GiElle, Gestione Letture), la directory 
del workspace sotto la quale creare il progetto ed in- 
fine il tipo di applicazione Stcmdalone o Depen- 
dent; nel nostro caso sceglieremo la prima delle 
due opzioni. Compilati i tre campi e cliccato il pul- 
sante "Create Project", si awierà un processo ab- 
bastanza veloce che creerà una directory "GiElle" 
nel nostro workspace di lavoro contenete il ne- 
cessario per la realizzazione del progetto stesso. 
In particolare sotto lib troviamo altre directory con- 
tenenti tutti i jar da cui JMatter dipende. Se aves- 
simo scelto Dependent non avremmo avuto tali jar 
ed avremmo dovuto aggiustare a nostro piacimento 
il classpath dell'applicazione stessa. La directory 
resources contiene alcune risorse tra cui le più im- 
portanti sono le immagini contenute sotto images 
(torneremo a parlare di questa directory). 
La directory src è quella in cui dovremo inserire le 
classi dell'applicazione, c'è da notare che tale directory 
contiene già alcuni file xml la cui semantica sarà 
discussa in seguito. Sotto GiElle troviamo anche 
un file build.xml che contiene target Ant pronti per 
l'uso. 



INDIVIDUARE 
IL DOMINIO 

Concentriamoci adesso sul dominio di business 
(model) della nostra applicazione. Ovvero cer- 
chiamo di individuare le entità che tratteremo e di 
cui il nostro progetto si servirà durante i suoi pro- 
cessi funzionali. L'entità centrale è rappresentata 
da Lettura che contiene i seguenti campi: 

• nome: nome della lettura 

• location: dove si trova 

• descrizione: descrizione della lettura 



• parole_chiavi: parole chiavi da utilizzare nelle 
ricerche 

• argomenti: argomenti trattati dalla lettura 

• tipologia: libro, rivista, pagina web 

I primi tre campi li possiamo considerare sempli- 
ci e ricondurli al tipo String (per il momento), an- 
che parole_chiavi lo possiamo considerare un'i- 
stanza di Stringimi stabiliamo da adesso che lo va- 
lorizzeremo con stringhe separate da spazi bianchi. 
Un discorso diverso va fatto per gli ultimi due cam- 
pi, infatti argomenti e tipologia possono essere ri- 
condotti a tipi composti. Il campo Tipologia per il 
momento lo consideriamo composto dal solo at- 
tributo nome. Argomenti invece ci induce a pen- 
sare ad un insieme di oggetti di tipo Argomento. 
Quest'ultimo avrà la seguente composizione: 

• nome: nome dell'argomento 

• descrizione: descrizione dell'argomento 

• letture: le letture che trattano questo argomen- 
to 

Poiché un argomento può essere trattato in diver- 
se letture ed analogamente una lettura può tratta- 
re diversi argomenti, possiamo stabilire fin da ora 
che la relazione tra Lettura ed Argomento è molti a 
molti. Mentre poiché una lettura afferisce ad una 
sola tipologia (o è un libro o è un articolo di una 
rivista e cosi via) possiamo stabilire che la relazio- 
ne che lega Tipologia e Lettura è uno a molti. 
Questo lavoro di analisi è fondamentale per l'uti- 
lizzo di JMatter, infatti da qui a poco impareremo 
che basta tradurre questi requisiti in linguaggio Ja- 
va per implementare la maggior parte delle fun- 
zionalità del software in questione. Iniziamo a scri- 
vere il codice necessario per la realizzazione della 
nostra applicazione; per prima cosa vediamo co- 
me è strutturata la classe Tipologia: 

@Persist 

public class Tipologia extends 

AbstractComplexEObject{ 
private final StringEO nome = new StringEO(); 
public static final String[] fieldOrder = {"nome"}; 
public Tipologia() {} 

public Title titleQ { 

return nome.title(); 

} 

public StringEO getNome() { 
return nome; 



> 



Già da questi primi passi ci si accorge che JMatter 
usa delle convenzioni per definire il meta-model (una 
sorta di descrizione del modello) con cui costrui- 
re l'applicazione. L'annotation @Persist indica al fra- 




DOPPIA 
LICENZA 

JMatter sembra 
aver pensato 
proprio a tutto, 
infatti il framework 
è distribuito con 
doppia licenza: GPL 
per gli amanti 
dell'operi source, e 
commerciale ad un 
prezzo di 500$ per 
gli sviluppatori che 
non vogliono 
rendere pubblico il 
codice 
implementato. 



http://www.ioprogrammo.it 



Dicembre 2007/ 47 ^ 



046-052:072-080 30-10-2007 15:58 Pagina 48 



SISTEMA T ■ Programmare con JMATTER 




SCRIPT 
DI LANCIO 

Il file Ant build.xml 

generato sulla root 

del nostro progetto è 

corredato da diversi 

target; il target 

shellscript è motlo 

utile, infatti una 

volta eseguito crea 

un file run.bat che 

consente di lanciare 

l'applicativo fuori da 

ambienti di sviluppo 

come Eclipse. 



-0- 



mework che le istanze della classe in questione sa- 
ranno memorizzate su DB ed esporranno funzio- 
nalità di lettura e scrittura. In pratica questa an- 
notation consente al framework di capire che l'en- 
tità in questione va mappata tramite Hibernate su 
una tabella del DB. 

Ogni entità del dominio deve essere rappresenta- 
ta da una classe che estende AbstractComplex- 
EObject; questa classe contiene l'insieme dei me- 
todi che avremmo dovuto ridefinire per ogni en- 
tità; basti pensare al mapping su DB e a come vie- 
ne visualizzata attraverso l'interfaccia grafica. In 
precedenza abbiamo detto che le istanze di Tipo- 
logia avranno un unico campo nome; ecco JMatter 
ha riscritto un insieme di tipi base (Atomic types) 
che replicano i tipi base del linguaggio Java. Il cam- 
po nome è dichiarato final ed è inizializzato im- 
mediatamente; ad esso corrisponde un metodo 
getNome che ritorna un oggetto di tipo StringEO. Tut- 
to ciò consente di avere un campo mai nuli e mo- 
dificabile dall'esterno solo invocando il metodo 
setValue(...) sull'oggetto restituito dal suo getter 



n 



■ s 



*# 


toturi 


■ • 


M 


■ • 


ri -uvei 


• # 


J* 


* * 


W4r 


* !■! 


tay*n* 


*« 


PrtftU**] 


* * 


IW-*-[*K 


* * 


■WhMt 


• * 


niHHD 


+ ■ j j-k ■ ■■ i ■ ruui 






* 4 


■ !■■■■■ !»■ 


■ • 




* m 


widMiK 


* * 


tfifftn* 


* ■ 


'. o. iu_uh 


• • 


™*-rt» 



41 



* 



(getNome). Ogni entità prevede anche un campo 
con la seguente signature: 

public static final String[] fieldOrder= {"nome"}; 

L'array di stringhe in questione serve a definire l'or- 
dine con cui verranno visualizzati i campi di una clas- 
se sull'interfaccia grafica; anche qui è prevista una 
corrispondenza tra i valori stringa assegnati agli 
item dell' array e i nomi dei campi della classe. Non 
ci resta che descrivere la semantica del metodo ti- 
tle; questo metodo serve ad identificare con una 
stringa le istanze di questa classe. Questo metodo 
è dichiarato abstract nella superclasse quindi sia- 
mo obbligati a definirlo per tutte le entità del no- 
stro modello. 



CODICE? GRAZIE, 
ma moni TROPPO 

Aumentiamo leggermente la complessità ed oc- 
cupiamoci di capire come è strutturata la classe 
Argomento. 

@Persist 

public class Argomento extends 

AbstractComplexEObject{ 
private final StringEO nome = new StringEOQ; 



private final StringEO descrizione = new 



StringEOQ; 



public static final String[] fieldOrder = 

{"nomeY'descrizione "/'letture"}; 
private final RelationalList letture = new 

RelationalList(Lettura. class); 
public static final Class lettureType = Lettura. class; 
public static final int lettureRelationType = 

PersistenceMechanism.MANY_TO_MANY; 
public static final String letturelnverseFieldName = 

"argomenti"; 



public RelationalList getLetture(){ 



return letture; 



public Argomento(){> 



public Title title(){ 



return nome.titleQ; 



public StringEO getNomeQ { 



return nome; 



public StringEO getDescrizioneQ { 



return descrizione; 



Figura 2: 1 tool messi a disposizione come target Ant. 



} 



Anche in questo caso possiamo notare la presen- 
za dell' annotation @Persist ed il fatto che la nostra 



+ 48 /Dicembre 2007 



http://www.ioprogrammo.it 



046-052:072-080 30-10-2007 15:58 Pagina 49 



Programmare con JMATTER ■ T SISTEMA 



classe estende AbstractComplexEObject; per en- 
trambi però la semantica è simile a quella analiz- 
zata per la classe Tipologia. Come abbiamo visto 
quando abbiamo definito il modello dell'applica- 
zione, questa classe è composta dai campi nome, 
descrizione e letture. Per i primi due c'è poco da di- 
scutere in quanto, come visto nel caso precedente, 
si usa il metodo get<nomeCampo> per accedere al 
valore, mentre si usa il metodo setValue per modi- 
ficarne il valore. In definitiva la vera novità è rap- 
presentata dal campo letture. Anch'esso è dichia- 
rato private final e prevede la definizione di un get- 
ter, il tipo con cui è dichiarato è RelationalList. Que- 
sta classe ci fa già intuire che si tratta di una lista di 
oggetti specializzata per mantenere relazioni tra 
oggetti appartenenti ad un determinato modello. 
Il tipo di oggetti contenuti in questa lista è specifi- 
cato sia nel costruttore sia nella dichiarazione 

public static final Class lettureType = Lettura. class; 



AbstractComplexEObject{ 



private final StringEO nome = new StringEO(); 
private final StringEO location = new StringEO(); 
private Tipologia tipologia= new Tipologia(); 
private final TextEO descrizione = new TextEO(); 

new 
StringEOQ; 



private final StringEO parole_chiavi 



private final RelationalList argomenti = new 

RelationalList(Argomento. class); 

In questa prima parte non troviamo niente di par- 
ticolare da annotare; infatti non abbiamo fatto al- 
tro che rispettare le convenzioni viste già in pre- 
cedenza. Abbiamo definito una classe le cui istan- 
ze saranno rese persistenti dal framework, ed ab- 
biamo definito i campi che ne determinano il con- 
tenuto di informazioni. Un piccolo appunto va fat- 
to per il campo descrizione, come possiamo nota- 
re è stato dichiarato di tipo TextEO. Questa classe 




-0- 



Come possiamo notare il nome attribuito ai vari 
campi della classe non è casuale, infatti anche in que- 
sto caso, la parte iniziale (letture) è identica al no- 
me della lista di cui si vuole specificare il tipo. Que- 
sto modus operandi può risultare a volte poco ele- 
gante ed un po' ridondante; l'autore del framework 
è consapevole di talune forzature sintattiche, pre- 
cisa che sono dovute a vari fattori quali la datazio- 
ne del framework anteriore alla definizione dei 
generics, e alla velocità con cui le API si sono evo- 
lute lasciando poco spazio al refactoring. Andan- 
do avanti nell'analisi del codice, possiamo osservare 
che la costante intera lettureRelationType serve a de- 
finire che la relazione definita dal campo letture è 
di tipo molti a molti; come nel caso precedente sia- 
mo vincolati nel definire il nome della costante. 
Altro codice degno di nota è il seguente: 

public static final String letturelnverseFieldName = 

"argomenti"; 

Sfruttando la reflection, quando il framework incontra 
questa dichiarazione capisce che la relazione è 
mantenuta anche in senso inverso, ovvero nella 
classe Lettura ci sarà un campo argomenti che man- 
terrà una relazione con la classe corrente. 



LA CLASSE LETTURA 

E' giunto il momento di dare uno sguardo alla clas- 
se principale che la fa da protagonista nella nostra 
applicazione; ovviamente stiamo parlando della 
classe Lettura. 

@Persist 

public class Lettura extends 



JMATTER E DB 



JMatter utilizza Hibernate per 
mappare le proprie classi sul DB, 
quindi è ovvio che ha la possibilità 
di utilizzare tutti i DB supportati 
da Hibernate. Di default però (per 
esempio nalla nostra applicazione) 
utilizza H2 database. Questo DB 
viene utilizzato in modalità 
embedded; ovvero non c'è 
bisogno di lanciare nessun server 



per il DB. Il DB infatti viene 
lanciato contestualmente 
all'esecuzione dell'applicazione. 
Per cambiare a proprio piacimento 
la tipologia di DB in cui 
memorizzare i dati, è sufficiente 
editare il file di proprietà 
hibernate.properties. Tale file è 
reperibile sotto la directory 
<GiElle>/resources. 



si differenzia da StringEO per due motivi princi- 
pali; il primo è che l'interfaccia grafica riserva un 
textfield per l'input dei dati di tipo StringEO, men- 
tre agli oggetti istanze di TextEO un textarea. L'al- 
tra differenza si riscontra nella memorizzazione 
su DB, per il tipo StringEO viene utilizzato un var- 




Figum 3: GiElle e la sua veste grafica. 



http://www.ioprogrammo.it 



Dicembre 2007/ 49 ^ 



046-052:072-080 30-10-2007 15:58 Pagina 50 



SISTEMA T ■ Programmare con JMATTER 




char(255) mentre per TextEO un tipo text (o affi- 
ne, dipende dal DB). Come avevamo stabilito in 
fase di design ad ogni istanza di Lettura è associa- 
ta una ed una sola istanza della classe Tipologia 
(relazione 1:1); mentre come avevamo stabilito per 
la classe Argomento, in questa classe abbiamo de- 
finito una lista di argomenti che serve a mantene- 
re la relazione molti a molti. 



public StringEO getNomeQ { 



return nome; 



public StringEO getParole_chiavi() { 
return parole_chiavi; 



■€+ 



AGGIUNGERE 
NUOVI UTENTI 

Nel nostro esempio 

abbiamo dato per 

scontato che 

l'utilizzatore si 

autentichi sempre 

come admin; è 

comunque possibile 

aggiungere nuovi 

utenti ed assegnare 

loro nuovi ruoli. 

L'interfaccia è molto 

intuitiva, basta 

loggarsi come admin 

aprire la sezione 

Admin e cliccare 

sull'icona Utenti e 

successivamente su 

Ruoli. 



public static final Class argomentiType = 

Argomento. class; 
public static final int argomentiRelationType = 

PersistenceMechanism.MANY_TO_MANY; 

public static String argomentilnverseFieldName = 

"letture"; 

public static final String[] fieldOrder = {"nome", 
"location", "tipologia", "descrizione", "parole_chiavi","ar 

gomenti"}; 

Anche il precedente codice Java non presenta no- 
vità rispetto alle conoscenze acquisite preceden- 
temente; in pratica le prime tre istruzioni servono 
a specificare il contenuto dell'oggetto argomenti. 
Mentre l'array di string lo ribadiamo serve a stabi- 
lire l'ordine con cui vengono presentati i dati nel- 
le form di modifica dei dati. Non ci stancheremo 
mai di dire che i valori delle costanti passati nel- 
l'array corrispondono e devono corrispondere ai 
nomi delle variabili istanze di classe. 

public Lettura(){> 

public Title title(){ 

return nome.title(); 

} 

public RelationalList getArgomenti() { 

return this. argomenti; 
} 



public Tipologia getTipologia() { 
return tipologia; 



public void setTipologia(Tipologia tipologia) { 
Tipologia tipO=this. tipologia; 
this. tipologia = tipologia; 
this.firePropertyChange("tipologia", tipO, 

tipologia); 



public TextEO getDescrizione() { 
return descrizione; 



public StringEO getl_ocation() { 
return location; 



Eccoci giunti all'ultima parte del codice della classe 
Lettura, i metodi in questione sono per la maggior 
parte dei casi i getters dei campi istanze di classe. Un 
caso particolare è rappresentato dal metodo set- 
Tipologia. Poiché tipologia è legata alla nostra classe 
con una relazione 1:1 è necessario notificare al fra- 
mework il cambiamento delle istanze di tale classe. 
Se analizziamo minuziosamente il suo codice 

Tipologia tipO=this. tipologia; 
this. tipologia = tipologia; 

possiamo notare che prima viene recuperato e me- 
morizzato nell'oggetto tipO il vecchio valore, dopo 
di che viene aggiornato il valore corrente con l'og- 
getto passato come parametro. Infine 

this.firePropertyChange("tipologia", tipO, tipologia); 

viene notificato ali 'erigine di eventi sottostante che 
la proprietà tipologia è cambiata, allo stesso en- 
gine vengono notificati sia il vecchio valore sia quel- 
lo nuovo. 



PURA MAGIA! 

Una volta scritte le classi che rappresentano il mo- 
dello del nostro dominio applicativo il lavoro del pro- 
grammatore è quasi finito. Questa affermazione, 
per quanto folle possa sembrare, è il vero vanto di 
cui si fregia JMatter. Ci manca davvero poco per 
vedere la nostra applicazione funzionante. 
Sotto la directory src esiste il file class-list.xml. Per 
rendere l'interfaccia grafica più fruibile bisogna 
modificare questo file. Nel file XML troviamo due 
occorrenze del tag folder, la prima contenente un 
tag name valorizzato a Model ed il secondo con il 
tag name valorizzato ad Admin. Bisogna editare il 
primo di questi tag in modo che sia valorizzato co- 
me di seguito. 





<folder> 


<name> 


v lodel</name> 




<items> 


<type>roby.jmatter.gielle 


.Tipologia</type> 


<type>roby.jmatter.gielle 


.Lettura</type> 



* 50 /Dicembre 2007 



http://www.ioprogrammo.it 



046-052:072-080 30-10-2007 15:58 Pagina 51 



Programmare con JMATTER ■ T SISTEMA 



-e- 



<type>roby.jmatter.gielle.Argomento</type> 

</items> 
</folder> 



In pratica questo file serve a specificare il posi- 
zionamento delle entità del modello nel menu 
di sinistra (class-bar). Nel nostro caso abbiamo 
cancellato le entità che sono già definite nel fra- 
mework e le abbiamo rimpiazzate con quelle im- 
plementate in questo esempio. Finalmente sia- 
mo pronti per vedere la nostra opera in esecu- 
zione. Dobbiamo prima lanciare il comando 

ant schema-export 

Questo comando trasforma le entità da noi im- 
plementate in tabelle e successivamente in tutti i 
file di configurazione Hibernate necessari per uti- 
lizzarle. Successivamente con 

ant run 

possiamo lanciare la nostra applicazione. Per pri- 
ma cosa vediamo che compare un form di login in 
cui ci vengono richieste le credenziali per accede- 
re al sistema. Utilizzando la coppia admin admin 
per username e password possiamo loggarci al si- 
stema. In figura 3 possiamo notare l'aspetto del- 
l'applicazione; abbiamo una class-bar sulla si- 
nistra, un normale menu in alto a sinistra ed una 
zona inizialmente vuota al centro. Il class-bar è 
T elemento con cui familiarizzare subito, infatti 
in esso sono definite due sezioni Model e Admin. 
La prima sezione l'abbiamo configurata in mo- 
do da presentare solo tre icone corrispondenti 
alle entità da noi introdotte, invece la sezione 
Admin è quella riservata alla configurazione del- 
l'applicativo stesso. Ogni icona della sezione Mo- 
del consente di eseguire un set di funzioni pre- 
definite, tra le quali: 

1. Elenca: visualizza tutte le entità presenti sul 
DB 

2. Nuovo: consente di creare una nuova entità 

3. Cerca: cerca le entità presenti sul DB tramite un 
form di immissione dati 

Esistono poi altre funzionalità che per una prima 
introduzione al framework possono essere tra- 
scurate. Se ritorniamo un attimo alle icone vi- 
sualizzate nella sezione Model possiamo nota- 
re che, contrariamente a quelle della sezione Ad- 
min, hanno tutte la stessa icona (quella di de- 
fault), inoltre sono etichettate con nomi errati 
(Tipologias, Letturas, Argomentos) ; questo er- 
rore è dovuto al fatto che il framework utilizza la 
sintassi inglese per determinare la versione al 
plurale dei nomi. Per ovviare a ciò ritorniamo ai 




^wr-r-^riji 

J-MHJfcl-MJI 




iSP» 



□ 
□ 



- 



^ — 



D 

□ 
D 
□ 
D 

□ 
□ 
D 



(i) 



Figura 4: Ecco la parte di amministrazione della nostra applicazione. 



VALIDAZIONE 



Se si fa qualche prova con 
l'applicazione che abbiamo creato, 
ci si accorge che abbiamo 
trascurato la validazione dei dati; 
supponiamo di voler introdurre 
una nuova Tipologia. Allora ci 
posizioniamo sulla relativa icona, 
tasto destro e scegliamo il 
comando Nuovo. A questo punto 
ci appare una form di immissione 
dati dove dovremmo inserire il 
nome della tipologia. Cosa 
succede se clicchiamo su Salva 
senza aver inserito nessun nome? 
Succede che il sistema accetta lo 
stesso questo inserimento e 
visualizza una Tipologia vuota. 
Allora la feature che dobbiamo 
aggiungere deve obbligare 
l'utente ad inserire almeno un 
carattere nella casella nome. Ci 
sono due modalità per inserire 
tale comportamento. Per utilizzare 
la prima basta andare sotto la 
directory <GiElle>/resources ed 
editare il file model- 
metadata.properties. Essendo un 
file di properties è sufficiente 
aggiungere il seguente codice: 

Tipologia, nome. required=true 

In questo modo, all'atto del 
salvataggio, il sistema ci segnalerà 
in modo standard che il campo 



nome non può essere vuoto. Per 
implementare una strategia di 
validazione customizzata bisogna 
scrivere un po' di codice; è 
sufficiente effettuare l'override 
del metodo validate nelle entità 
implementate. Nel nostro caso 
dobbiamo aggiungere il seguente 
codice alla classe Tipologia. 

public int validate(){ 



String 

s=this.getNome().stringValue(); 



if(s==null || s.trim().equals("")){ 



fireValidationException("Inserisci un 

nome non vuoto!"); 



return 1; 



} 



return 0; 



} 



Il metodo effettua un controllo sul 
campo nome dell'oggetto, se il 
suo valore è nuli o uguale ad una 
serie di spazi bianchi segnala 
all'utente un messaggio ad-hoc. Lo 
stato della validazione è 
determinato dal valore ritornato 
dal metodo; segnala che la 
validazione è andata a buon fine 
mentre un qualsiasi altro intero 
segnala che la validazione non ha 
dato esito positivo. 



http://www.ioprogrammo.it 



Dicembre 2007/ 51 ^ 



046-052:072-080 30-10-2007 15:58 Pagina 52 



SISTEMA T ■ Programmare con JMATTER 




-e- 




Roberto Sidoti è 
Ingegnere 
Informatico, in passa- 
to si è occupato di ser- 
vizi VolP; attualmente 
è Functional Designer 
per Herzum Software, 
una multinazionale di 
consulenza specializza- 
ta nello sviluppo di 
componenti per appli- 
cazioni SOA. Negli ulti- 
mi mesi lavora per il 
progetto FourthCodex, 
che è una piattaforma 
di ultima generazione 
per la gestione di con- 
tenuti semantici. 



sorgenti delle tre classi ed aggiungiamo il se- 
guente codice: 

public static String pluralName() { return "Letture"; } 

Ovviamente per la classe Tipologia usiamo la strin- 
ga "Tipologie" e per la classe Argomento la strin- 
ga "Argomenti". Per quanto riguarda invece l'utilizzo 
di icone distinte e personalizzate per le varie en- 
tità la soluzione è ancora più semplice. Infatti ba- 
sta munirsi di due immagini per entità aventi il no- 
me così formato: 

<nome_entità>16.png 
< nome_entità > 32 . png 

La prima avrà dimensione 16 x 16 e la seconda 
32 x32. Questi file vanno inseriti all'interno del- 
la directory <GiElle>/resources/images, sarà 
compito del framework caricarle ed associarle 
alle entità giuste. 

Un altro miglioramento che possiamo facil- 
mente apportare alla veste grafica è l'utilizzo di 
un splash screen in fase di caricamento del- 
l'applicazione. Anche in questo caso è suffi- 
ciente munirci di un file splash.png (anche i for- 
mati gif e jpg vanno bene) e posizionarlo nella 
directory <GiElle>/resources/images. 



COMANDI AGGIUNTIVI 

JMAtter potrebbe somigliare ad un bel framework 
che prevede un set di funzionalità preconfe- 
zionate, che però poco si presta all'implemen- 
tazione di funzionalità che vanno oltre le sem- 
plici operazioni su DB. Questa convinzione va 
subito smentita, JMatter consente allo sviluppatore 
di definire delle funzionalità customizzate che 
si possono aggiungere alle varie entità del dominio 
applicativo. Vista la natura didattica dell'arti- 
colo ci limiteremo a definire un semplice co- 
mando con poca valenza semantica, infatti lo 
utilizzeremo per cancellare il campo descrizio- 
ne della classe Lettura. Non è oggetto di questo 
articolo ma va detto che il framework offre la 
possibilità di accedere tramite HQL ai dati sul DB. 

@Cmd(mnemonic='c') 

public String Cancella_Descnzione(CommandInfo 

cmdInfo){ 

this. descrizione. setValue(""); 

this.save(); 

return "La descrizione è stata cancellata"; 
} 

La sintassi prevista è semplicissima, per prima 
cosa va definito un metodo il cui nome corri- 



sponde all'etichetta che intendiamo visualiz- 
zare sulla form. In questo caso il carattere "_" 
sarà rimpiazzato dal carattere " ". Per questo 
metodo va definita una annotation @cmd che 
indica al framework che il metodo successivo 
implementa la gestione di un custom command. 
Il carattere "e" sarà utilizzato come shorteutper 
l'esecuzione del comando. Di default il fra- 
mework associa i custom command alla form 
di lettura (visualizzazione) degli oggetti; per uti- 
lizzare comandi personalizzati in altre form è 
possibile aggiungere porzioni di codice simili 
al seguente. 

static{ 
ComplexType type = 

ComplexType.forClass(l_ettura. class); 
Command cmd = new 

Lettura().command("Cancella_Descrizione "); 
type. commands(ReadState. class), remove(cmd); 
type. commands(EditState. class). add(cmd); 
} 

La semantica è molto semplice, una volta indivi- 
duato il comando introdotto in precedenza lo si 
rimuove dallo stato ReadState e lo si aggiunge per 
lo stato EditState. 



CONCLUSIONI 

In questo articolo abbiamo imparato ad utiliz- 
zare un framework che segue i dettami del pat- 
tern Nacked Object. Abbiamo visto che il fra- 
mework è utilissimo sia alla prototipazione sia 
alla realizzazione vera e propria di progetti 
software. Certamente il suo utilizzo per certi 
aspetti imbriglia la fantasia degli sviluppatori; 
questo fattore però va valutato positivamente 
in quanto gli stessi potranno concentrarsi solo 
sulla parte di business logie senza perdere tem- 
po sulle altre parti. Un altro aspetto che vi con- 
sigliamo di tenere in considerazione è la con- 
tinuità con cui questo framework viene aggior- 
nato; infatti allo stato attuale il framework è ef- 
ficiente e funzionante ma vi sono un paio di 
macro-feature che la comunità, che lo segue, si 
è riproposta di implementare. Si tratta della pos- 
sibilità di avere un client web Ajax (magari uti- 
lizzando Echo2) e di estendere l'attuale architettura 
client/ server magari utilizzando il remoting di 
Spring. E' inutile sottolineare che la conoscen- 
za di tale framework e il fascino della program- 
mazione in Java possano essere un buon input 
per indurre i nostri lettori alla partecipazione 
attiva in questo progetto open source. 

Roberto Sidoti 



+ 52 /Dicembre 2007 



http://www.ioprogrammo.it 



054-059:040-043 Networking 2-11-2007 11:50 Pagina 54 



Networking T H I protocolli che fanno muovere la rete 



REALIZZARE UN 
INSTANT MESSENGER 

LO SVILUPPO DI UN INSTANT MESSENGER PUÒ ESSERE UN'ATTIVITÀ MOLTO INTERESSANTE 
CHE CI PERMETTERÀ DI ADDENTRARCI NEI MEANDRI DEL NETWORKING E DI REALIZZARE 
UN'APPLICAZIONE DI IMMEDIATO UTILIZZO PRATICO 




LI CD (J WEB 

JavaNetworking.zip 



-0- 



REQUISITI 



MéJMWMMUJUm 
Basidi Java 



J2SE 



Tempo di realizzazione 



0000O 




Tutte le comunicazioni che avvengono su 
internet sono basate sul protocollo TCP/IP 
che è lo standard "de facto" nel campo del 
networking. Quando si parla di TCP/IP ciò che è fon- 
damentale tenere presente è il concetto di "strati", o 
all'inglese "layers", che sta alla base del funziona- 
mento del TCP/IP In effetti lo stesso nome TCP/IP 
deriva dagli ultimi due layers del protocollo stesso. 
Mettiamo che A voglia inviare una mail a B: l'appli- 
cazione (liv. 7) di A propagherà il messaggio usando 
il layer sottostante (liv. 6), e che a sua volta userà il 
layer inferiore, fino ad arrivare alla comunicazione 
sul mezzo fisico. A sua volta dalla parte di B il mes- 
saggio verrà propagato dal liv. 1 fino al liv. 7. In altre 
parole ciò significa che ogni qual volta abbiamo la 
necessità di sviluppare un'applicazione che debba 
comunicare attraverso internet dovremo semplice- 
mente "agganciarci" al layer più in alto dello stack 
TCP/IR ossia il TCP (gli altri protocolli "fratelli" del 
TCP, come UDP o ICMP, esulano dagli scopi di que- 
st'articolo ma il concetto sarebbe comunque il 
medesimo). 

Una volta appurato ciò il passo successivo dovrebbe 
essere quello di chiedersi: 

Come si fa nel concreto ad attaccarsi a questo stack 
di protocollo di comunicazione? 
Ho voluto appositamente utilizzare il verbo attac- 
carsi perché esso rende bene l'idea su cosa si fonda- 
no i socket. Il termine socket in inglese significa 
"presa" , "attacco". 

E' in effetti come una porta di comunicazione, con- 
cettualmente simile ad una presa elettrica: qualsiasi 
cosa progettata per comunicare tramite il protocol- 
lo standard TCP/IR può collegarsi ad un socket e 
comunicare tramite questa porta di comunicazio- 
ne, così come un qualsiasi apparecchio elettrico ali- 
mentato con la corrente 220 può collegarsi ad una 
presa elettrica a muro e sfruttare la tensione che la 
rete di distribuzione elettrica mette a disposizione. 
Nel mondo dei socket potremmo dire che la rete di 
distribuzione è internet stessa ed invece dell' elettri- 
cità, nella rete viaggiano pacchetti TCP/IP 
Grazie a questo meccanismo quindi possiamo com- 
pletamente disinteressarci a cosa si celi dietro ad un 



socket (proprio come non ci poniamo il problema di 
cosa ci sia dietro la presa dell'elettricità, almeno fin 
quando tutto funziona!), rendendo quindi del tutto 
trasparente l'esistenza stessa dello stack. 
Scendendo più nel dettaglio di come sono fatti que- 
sti socket potremmo iniziare con l'affermare che essi 
sono identificabili da una coppia di parametri: 

• l'indirizzo ip del host 

• il numero di porta TCP 

solitamente la sintassi prevede che questi elementi 
che compongono una coppia univoca siano separa- 
ti dai due punti (:). Ad esempio se volessimo aprire 
un socket verso il nostro web server dovremmo spe- 
cificare l'indirizzo 127.0.0.1:80. 
Come avrete capito anche da quest'ultimo esempio, 
è necessario che i due interlocutori comunichino 
sulla stessa porta contemporaneamente! Altrimenti 
chi manda il messaggio troverebbe la "porta chiusa" 
dell'altro e viceversa. Da qui nasce l'esigenza del 
paradigma client - server. 



JAVA ED I SOCKET 

Per concludere la sintesi necessaria a fornire gli ele- 
menti per lo sviluppo della nostra applicazione 
vediamo in che modo Java supporti i socket. Le API 
di Java prevedono proprio questi due interlocutori 
(client - server). Rivediamo quindi brevemente le 
due classi in questione e come esse comunicano. 
Riporto l'esempio del server che risponde riman- 
dando indietro i messaggi inviatigli dal client. 

public class EchoServer implements Runnable { 
public static final int PORT = 4422; 
private ServerSocket sSocket = nuli; 



public void run() { 



try{ 



sSocket = new 

ServerSocket(PORT); 



Socket clientSocket = nuli; 



* 54 /Dicembre 2007 



http://www.ioprogrammo.it 



054-059:040-043 Networking 30-10-2007 17:23 Pagina 55 



I protocolli che fanno muovere la rete ■ T Networking 



PrintWriter out = nuli; 



BufferedReader in = nuli; 



running = true; 



try{ 



while (loop) { 



clientSocket = 
sSocket.acceptQ; 



out = new 
PrintWriter(clientSocket.getOutputStream(),true); 

in = new 
BufferedReader(new 
InputStreamReader(clientSocket.getInputStream())); 



String line; 



while ((line = 
in.readLineQ) != nuli) 



out.println("Server response: "+ line); 



} 



} catch (IOException e) { 



e.printStackTraceQ; 



System. err.println("Server is 



down"); 



-0- 



} 



In poche parole si istanza un oggetto di tipo 
ServerSocket indicando al costruttore su quale porta 
debba rimanere in ascolto. Il momento in cui però 
esso si mette effettivamente in ascolto è solo al 
momento dell'invocazione del metodo acceptQ che 
restituisce il socket del client che ha effettuato la 
richiesta. La comunicazione con quest'ultimo viene 
quindi realizzata semplicemente leggendo e scri- 
vendo sugli stream di input ed output del client stes- 
so. Infatti vista da lato client la comunicazione 
avviene nel seguente modo: 



public static void main(String[] args) throws 



IOException { 



Socket echoSocket = nuli; 



PrintWriter out = nuli; 



BufferedReader in = nuli; 



try{ 



echoSocket = new 

Socket("127.0.0.1", PORT); 

out = new 
PrintWriter(echoSocket.getOutputStream(), true); 
in = new BufferedReader(new 

InputStreamReader( 



echoSocket.getInputStream())); 



} 



BufferedReader stdln = new BufferedReader( 



new 
InputStreamReader(System.in)); 



String userlnput; 



stdln. readUne()) != nuli) { 


if(userlnput.equals("")) 

{ 


serverSocket.stop(); 


break; 


} 


out.println(userlnput); 


System. out.println(in 


.readLine()); 


} 



Cioè un client non fa altro che puntare ad una ben 
precisa porta di un ben preciso indirizzo e scrivere e 
leggere sui propri stream, sapendo che dall'altra 
parte c'è un server in ascolto. 



IL MOSTRO IIUSTAIUT 



while ((userlnput : 



Dovremmo ormai quindi avere tutte le informazioni 
e conoscenze per affrontare lo sviluppo dell'applica- 
zione che vogliamo realizzare: un Instant 
Messenger! 

Sicuramente è naturale che al mondo non è che ci 
sia bisogno di un ulteriore programma di chat, ma 
affrontando questo progetto abbiamo l'opportunità 
di toccare con mano una considerevole serie di tec- 
niche di networking riutilizzabili poi nei più dispa- 
rati contesti. 

D'altra parte poiché un intera infrastruttura per un 
programma completo di messaggistica richiedereb- 
be probabilmente ben più di una serie di articoli 
lasceremo fuori quegli aspetti che non riguardano 
strettamente il networking, in particolare non ci 
occuperemo di: 

1. Modulo di autenticazione con password 

2. Gestione del database degli utenti e delle liste 
contatti 

Ora che abbiamo definito bene i confine della nostra 
applicazione possiamo iniziare a sviluppare le parti 
che la comporranno. 



UN'ARCHITETTURA P2P 

L'esempio introduttivo ai socket mostrava l'utilizzo 
di un'architettura client / server; nel caso di un siste- 
ma di messaggistica diretto le cose dovranno essere 
diverse, infatti sarebbe più appropriato adottare 
un'architettura peer to peer (p2p) Cominciamo con 
un'analisi generale per poi scendere nel dettaglio di 
ogni singolo modulo. 

• Quando si invia un messaggio tramite il bottone 
"send" ) la GUI si comporterà da client ed aprirà 
un socket verso l'indirizzo dell'altro utente 




http://www.ioprogrammo.it 



Settembre 2007/ 55 + 



054-059:040-043 Networking 30-10-2007 17:23 Pagina 56 



Networking T ■ I protocolli che fanno muovere la rete 




-e- 



• In fase di ricezione sarà necessario avviare il ser- 
ver come demone e metterlo in ascolto su una ben 
determinata porta. Una volta accettata una con- 
nessione da parte del client socket dovrà spedire il 
messaggio ricevuto alla GUI del proprio stack. 

• La comunicazione per questa applicazione è sicu- 
ramente di complessità maggiore rispetto a quel- 
la del nostro primo esempio in cui il server si limi- 
tava a "fare l'eco" al client. Da qui nasce quindi l'e- 
sigenza di prevedere un protocollo che si occupi 
dell'elaborazione del messaggio. Tale compito 
sarà assolto da una classe che lavorerà in stretta 
coppia con il server. 

• Il messaggio così elaborato sarà posto su una coda 
messa a disposizione dalla GUI. Uno spooler si 
occuperà di controllare tale coda ed andare a scri- 
vere il messaggio sulla GUI stessa. 

Come potete vedere un messaggio fa un bel giro 
prima di arrivare dall'altro utente. Seguiamo allora 
tale percorso proprio attraverso il codice. 



SPEDIRE URI MESSAGGIO 
DALL'ALTRA PARTE 

Appena aperta l'applicazione viene chiesto di inseri- 
re un nickname che identificherà l'utente durante 
tutta la sessione di comunicazione (figura 4). Tale 
nome viene passato al costruttore della GUI princi- 
pale che lo memorizza come campo privato. 

public class IMGUI extends javax. swing JFrame { 



public IMGUI(String name) { 



super(); 



userName = name; 



initGUI(); 



queue = new 

SynchronousQueue<Message>(); 



Viene inoltre istanziata una coda sincrona dove ver- 
rano recapitati i messaggi in entrata per l'utente. La 
classe SynchronousQueue è un generic e quindi il 
relativo oggetto è stato proprio creato specificando 
la classe Message come argomento del template. 
Oltre a questa coda sarà necessario creare ed avvia- 
re i thread per il server socket e lo spooling della 
coda: 



e.getMessage(), "ERROR", 
JOptionPane.ERROR_MESSAGE); 



} 



spooler = new Thread(new 

Runnable(){ 



public void run() { 



spoolQ; 



»; 



spooler.setDaemon(true); 



spooler. sta rt(); 



Il codice sottostante il bottone send è molto simile 
alla parte client vista nell'esempio precedente: 



private void jButtonSendMouseClicked(MouseEvent 



evt){ 



if(client == nuli) 



client = new 
IMCIient(userName,jTextFieldHost.getText(),Integer.p 
arseInt(jTextFieldPort.getText())); 



String message = 

jTextFieldMessage.getTextQ; 



try{ 



client. send(message); 



jEditorPaneChat.getDocument().insertString(jEditor 

PaneChat.getDocument().getl_ength(), "[Me] " + 
message+"\n", nuli); 



jTextFieldMessage.setText(""); 



} catch (UnknownHostException 



e){ 



JOptionPane.showMessageDialog(this, 

e.getMessage(), "error", 
JOptionPane.ERROR_MESSAGE); 



} catch (IOException e) { 



JOptionPane.showMessageDialog(this, 

e.getMessage(), "error", 
JOptionPane.ERROR_MESSAGE); 



} catch (BadLocationException e) 



{ 



JOptionPane.showMessageDialog(this, 

e.getMessage(), "error", 
JOptionPane.ERROR_MESSAGE); 



} 



try{ 



serverDaemon = new 
Thread(new IMServer(4422, queue)); 



serverDaemon. setDaemon(true); 



serverDaemon. sta rt(); 



} catch (IOException e) { 



JOptionPane.showMessageDialog(this, 



La prima cosa da premettere è quella che la comu- 
nicazione criptata attraverso tunnel SSH non verrà 
trattata nel presente articolo, bensì costituirà l'og- 
getto principale del prossimo. Per cui, facendo rife- 
rimento alla figura 5, potete completamente ignora- 
re tutte le opzioni riguardanti la connessione SSH. 
Naturalmente anche nel codice verranno quindi 



* 56 /Dicembre 2007 



http://www.ioprogrammo.it 



054-059:040-043 Networking 30-10-2007 17:23 Pagina 57 



I protocolli che fanno muovere la rete H T Networking 



omesse quelle parti in cui si fa riferimento a tale 
opzione; in altre parole riportiamo il codice che 
viene eseguito quando la checkbox per l'abilitazione 
del tunnel SSH. 

Per quanto riguarda l'invio del messaggio, il codice è 
veramente semplice: 

• Se ancora non lo si è fatto si istanzia un oggetto del 
tipo IMClient a cui viene passato l'indirizzo IP ed 



if (s != nuli) s.closeQ; 




Fig. 1: Finestra di login che appare all'avvio dell'appli- 
cazione 



} 



Come ormai abbiamo già più volte visto, la comuni- 
cazione avviene attraverso gli stream della coppia 
client / server. 

Andiamo quindi per ordine e vediamo come il lato 
server, ossia la classe IMServer, integri questa volta 
al proprio interno anche la classe che si occupa della 
gestione del protocollo di comunicazione. 



UM SERVER ED 
UHI PROTOCOLLO 
DI COMUNICAZIONE 

Quando si utilizza una classe che si fa carico della 
gestione logica della comunicazione si ottiene come 
conseguenza che la complessità della classe che 
funge da server vero e proprio si riduce drastica- 
mente. Infatti ecco come si presenta la classe server: 




public class IMServer implements Runnable { 



-0- 



il numero di porta dell'utente con cui vuole 
comunicare recuperandoli dalle relative textbox. 

• Leggere il messaggio e passarlo all'invocazione 
del metodo send 

• Inserire il messaggio anche nel pannello dove 
viene riportato tutto le storico della chat. 

Il metodo send della classe IMClient è così imple- 
mentato: 

public void send(String text) throws 

UnknownHostException, IOException { 
PrintWriter out = nuli; 
Socket s = nuli; 
int portToConnect; 
String hostToConnect; 



portToConnect = port; 



hostToConnect = host; 



try{ 



s = new 
Socket(hostToConnect,portToConnect); 



out = new 
PrintWriter(s.getOutputStream(),true); 
out.println(T + user + 

"] " + text); 

} catch (UnknownHostException 



e){ 



throw e; 



} catch (IOException e) { 



throw e; 



} finally { 



if (out != nuli) 



out.closeQ; 



public IMServer(int port, 

SynchronousQueue<Message> queue) throws 

IOException 



{ 



PORT = port; 



this. queue = queue; 



server = new 



ServerSocket(PORT); 



protocol = new IM Protocol (); 




Fig. 2: Sessione di chat tra due utenti 



Vedremo tra pochissimo a cosa serve la coda passa- 
ta al costruttore, per ora diamo un'occhiata a quali 
azioni compie il server appena viene lanciato: 



while (loop) { 


try{ 


Socket socket 
= server.accept(); 


Message m = 
protocol . process(socket) ; 


queue. add(m); 



http://www.ioprogrammo.it 



Dicembre 2007/ 57 ^ 



054-059:040-043 Networking 30-10-2007 17:23 Pagina 58 



Networking T ■ I protocolli che fanno muovere la rete 




-e- 







if(socket ! 


nuli) 


socket.close(); 




} catch (IOException 


e) 
{ 


System. err.println(e.getMessage()); 


} 


} 



Tutto qui! Infatti sarà l'oggetto protocol a trattare le 
informazioni ricevute tramite il socket del client ed a 
restituire un altro oggetto di tipo Message. 
Quest'ultimo viene poi accodato nell'oggetto queue 
passatogli dalla GUI. È, a mio avviso, importante 
sottolineare questo aspetto: introducendo la classe 
IMProtocol non ci siamo limitati a spostare il codice 
da una classe all'altra, abbiamo bensì disaccoppiato 
due compiti ben distinti. Infatti una cosa è tenere 
aperta una porta sullo stack TCP/IP ed instradare le 
comunicazioni su di essa, altro è gestire la logica con 
cui la comunicazione avviene. In questo modo se si 
volesse modificare il protocollo di comunicazione 
basterà implementare nuovamente il metodo pro- 
cess lasciando inalterato tutto il resto. 
Infine sarà poi compito del metodo di spooling 
quello di andare a prelevare i messaggi dalla coda e 
scriverli sul pannello della chat ). 
Procediamo con ordine analizzando prima di tutto 
la classe protocol: 



public class IMProtocol { 



public Message process(Socket sender) { 



BufferedReader reader = nuli; 



try{ 



reader = new 

BufferedReader(new 
InputStreamReader(sender.getInputStream())); 



StringBuilder sb = new StringBuilder(); 

String line; 
while((line = reader.readLineQ) != nuli) 



sb.append(line); 



Message m = 
createMessage(sb.toString()); 



m.setSenderIP(sender.getRemoteSocketAddress() 

.toString()); 
return m; 



} catch (IOException e) { 



} finally 



{ 



if( reader != nuli) 



try{ 



reader.closeQ; 



} catch 
(IOException e) { 



e.printStackTraceQ; 



} 



La logica di tale metodo è abbastanza semplice, 
viene creato un oggetto di tipo Message e si valoriz- 
zano i campi da esso previsti, in particolare gran 
parte di ciò viene nel seguente metodo: 

private Message createMessage(String text){ 

Message m = new Message(); 
m.setText(text); 
m.setReceptionDate(new 
java.util.Date(System.currentTimeMillis())); 
return m; 



LO SPOOLING 
DELLA CODA 

È stato già visto che il server è un thread demone 
rispetto all'applicazione principale, quindi si è pre- 
sentata la necessità di far comunicare questi ultimi 
due. L'oggetto più indicato per assolvere tale compi- 
to è sicuramente SynchronousQueue. Infatti, ripor- 
tando quanto scritto nella documentazione ufficiale 
della SUN per le API Java, una SynchronousQueue è 
una BlockingQueue nella quale ogni invocazione del 
metodo put deve aspettare l'invocazione del meto- 
do take e viceversa. 

Come avrete sicuramente notato il server, per inseri- 
re un messaggio sulla coda, fa uso del metodo add 
anziché di put. Il motivo di tale scelta è molto sem- 
plice: non vogliamo assolutamente che il server si 
blocchi su questo metodo finché dall'altra parte 
qualcuno (nella fattispecie lo spooler della GUI) 
invochi il metodo take. 

Nella situazione diametralmente opposta si trova 
invece lo spooler. Infatti lo spooler non deve fare 
niente, ossia deve attendere, finché la coda non con- 
tiene almeno un messaggio. Una volta preso, lo 
dovrà poi scrivere sul pannello della chat. Anche in 
questo caso risulta naturalmente necessario che lo 
spooler sia anche esso un demone figlio del thread 
principale della GUI. Vediamo quindi come quanto 
detto finora sia stato implementato: 

public IMGUI(String name) { 



spooler = new Thread(new 

Runnable(){ 



public void run() { 



spoolQ; 



»; 



spooler.setDaemon(true); 



spooler.startQ; 




.:--■ 



4 

- 



} 



* 58 /Dicembre 2007 



http://www.ioprogrammo.it 



054-059:040-043 Networking 30-10-2007 17:23 Pagina 59 



I protocolli che fanno muovere la rete H T Networking 



Al momento della creazione della GUI viene creato il 
demone di spooling e lanciato. Essendo un demone 
il suo compito non è altro quello di effettuare un 
loop infinito per controllare la coda: 

private void spool() { 

while (true) { 

tryj 

Message m = queue.take(); 

int length = 

jEditorPaneChat.getDocument().getLength(); 

String text = m.getText(); 
SimpleAttributeSet att = new SimpleAttributeSet(); 



StyleConstants.setItalic(att, true); 



jEditorPaneChat.getDocument().insertStnng(length, 

text+"\n", att ); 



} catch (Exception e) { 



JOptionPane.showMessageDialog(this, 

e.getMessage(), "error", 
JOptionPane.ERROR_MESSAGE); 



} 



} 



} 



L'invocazione del metodo take farà sì che il loop 
determinato dal ciclo while (true) si blocchi in que- 
sto punto ed attenda finché un messaggio non viene 



inserito nella coda. Una volta ricevuto il messaggio 
ne formatterà il contenuto e lo inserirà come ultima 
riga nello storico della chat. 



CONCLUSIONI 

Ora, per concludere, possiamo quindi porci qualche 
domanda interessante: 

1 - Tra l'utente "Pippo" e l'utente "Pluto" cosa c'è in 
mezzo? Ossia siamo sicuri che l'applicazione funzio- 
ni allo stesso modo indipendentemente dal numero 
di nodi che si frappongono tra i due? 

2 - Se qualcuno si mettesse a fare sniffing sulla porta 
da noi scelta, quanto riuscirebbe a capire di quello 
che stiamo scrivendo? 

3 - Un port scannig sul pc nel quale stiamo ese- 
guendo l'applicazione che conseguenze potrebbe 
avere e come ci potremmo nascondere da una simi- 
le indagine maliziosa? 

A tutto questo daremo risposta nella prossima pun- 
tata. 




REALIZZARE 
L'INTERFACCIA 

ONon rientra negli 
scopi dell'articolo la 
spiegazione dello 
sviluppo di 
un'interfaccia grafica 
con la libreria swing. A 
titolo di cronaca per 
realizzare questa 
applicazione mi sono 
avvalso dell'IDE 
Eclipse e del relativo 
plugin Jigloo. 




FUTURA 



Via Adige, 11 - 21013 CALLARATE (VA) - Tel. 0331/799775 - Fax. 0331/778112 



060-066:072-080 30-10-2007 16:19 Pagina 60 



SISTEMA T ■ Visual Studio ed il Refactoring 



RIPROGRAMMARE 
IL CODICE CON STILE 

HAI SCRITTO IL TUO FANTASTICO SOFTWARE. ORA TI ACCORGI CHE AVRESTI POTUTO USARE 
NOMI PIÙ SIGNIFICATIVI. COME MIGLIORARE IL TUO SOFTWARE SENZA DOVER CAMBIARE 
MANUALMENTE TUTTI I RIFERIMENTI? A QUESTO È A MOLTO ALTRO CI PENSA IL REFACTORING! 



-0- 



.net 



n 




REQUISITI 



I II I I 'i ^ 

- Visual Studio 2005 e C# 



Windows XP Service 
Pack 2, Windows 
Server 2003 o 
Windows Vista - .NET 
Framework 2.0, Visual 
Studio 2005 (standard 
o professional). 



_i_^d .=d 



Tempo di realizzazione 



Il Refactoring può essere definito come una 
qualsiasi modifica al codice sorgente di un 
programma per computer che ne migliora la 
leggibilità o ne semplifica la struttura senza però 
modificarne il funzionamento e quindi il risultato. 
Da questa definizione traiamo immediatamen- 
te il significato di Refactoring e quanto quindi 
questo processo sia importante per migliorare 
il nostro lavoro. Non esistono delle vere e pro- 
prie liste di regole per il refactoring scolpite nel- 
la roccia ma esistono una serie di buone prati- 
che di programmazione che se seguite permet- 
tono di produrre codice di qualità facilmente 
estendibile, leggibile e manutenibile. Quindi co- 
me spesso avviene in rete, nel tempo alcune di que- 
ste pratiche sono entrate nell'uso comune ed es- 
sendosi rivelate utili nonché sufficientemente 
testate sono state formalizzate sotto forma di re- 
factoring nel libro: Refactoring: Improving the 
Design ofExisting Code di Martin Fowler. Mi- 
crosoft, dal canto suo, è ben conscia dell'impor- 
tanza del processo di refactoring del codice e di 
conseguenza con il rilascio della versione 2005 di 
Visual Studio ha introdotto tutta una serie di fun- 
zionalità per aiutare il programmatore in tal sen- 
so. E non solo per il codice di programmazione, 
infatti la versione for Database Professionals di 
Visual Studio Team Edition comprende anche 
una funzionalità di refactoring specifica per i da- 
tabase che consente di rinominare una colonna 
di una tabella aggiornando di conseguenza an- 
che tutti i riferimenti alla stessa ad esempio nel- 
le stored procedure. 

Prima dell'arrivo dei tool, tra cui Visual Studio 2005, 
il lavoro di refactoring del codice era abbastanza 
lungo e laborioso e richiedeva un pesante inter- 
vento manuale nel codice. Inoltre l'intervento ma- 
nuale facilmente poteva portare all'introduzione 
di errori senza contare la consistente perdita di 
tempo. Grazie ai tool di refactoring ed in partico- 
lare a Visual Studio 2005, oggi è possibile effettua- 
re questo processo con una semplicità mai vista 
prima. Con pochi click del mouse è possibile mo- 
dificare una intera soluzione senza che questo com- 



porti l'introduzione di errori e senza perdita di tem- 
po. Vediamo quindi quali sono queste funzioni che 
Visual Studio 2005 ci mette a disposizione e quan- 
do utilizzarle. 



LE TECNICHE 

DI REFACTORING 

Vediamo quindi dettagliatamente quali sono le tec- 
niche di refactoring presenti in Visual Studio 2005 
ed alcuni esempi che ci permetteranno di capire 
quando è opportuno applicarle. Innanzi tutto ve- 
diamo un elenco sintetico dei refactoring insieme 
ad una loro breve descrizione: 

• ExtractMethod 

Permette di creare un nuovo metodo a partire 
dal codice selezionato 

• Encapsulate Field 

Converte un campo pubblico in un campo pri- 
vato esposto da una proprietà 

• Extract Interface 

Crea una interfaccia sulla base di un gruppo di ti- 
pi esistenti 

• Reorder Parameters 

Consente di riordinare i parametri di un metodo 

• Remove Parameters 

Consente di rimuovere un parametro da un me- 
todo 

• Renarne 

Permette di rinominare un elemento (un meto- 
do, una classe, una proprietà, . . .) all'interno del- 
l'intero progetto 

• Promote Locale Variable to Parameter 
Converte una variabile locale in un parametro 
del metodo in cui è contenuta 

• Generate Method Stub 

Crea un metodo a partire da una sua chiamata. 

Tutte queste funzioni, tranne l'ultima, in Visual 
Studio 2005 sono accessibili sia tramite l'apposito 
menu Refactor che tramite il menu contestuale vi- 
sualizzato cliccando con il tasto destro del mouse 



* 60 /Dicembre 2007 



http://www.ioprogrammo.it 



060-066:072-080 30-10-2007 16:19 Pagina 61 



Visual Studio ed il Refactoring ■ T SISTEMA 



— 



-0- 



*- - 




u ||i hnh 



■ iv. il ri^ ir *j 



Figura 1: Menu Refactor 



1 


■ Hill .PIMI - Ul 1 






1 pri 


-*- 


i 


■< 


^J^^_ 




*. 


MM ■ 




- 


bhUb- 


■ 


■ 


h«r ■ 


1 


* 


■ ■ ■ 



3-f — 



A *p 



Figura 2: Menu contestuale dei refactor 



all'interno del codice. 

L'unica eccezione è il comando Generate Method 
Stub che invece appare sempre nel menu conte- 
stuale ma fuori dal gruppo di voci Refactor oppu- 
re all'interno del codice tramite la funzionalità di 
Automatic Code Generation dell'IntelliSense di- 
rettamente sulla chiamata al metodo 



::E 



l^nr.Lii 



Figura 3: Comando Generate Method Stub 



EXTRACT METHOD 

La tecnica di refactor Extract Method ci permette di 
estrapolare un nuovo metodo da una porzione di 
codice esistente. Accade sovente durante lo svi- 
luppo di scrivere porzioni di codice che in qual- 
che modo possono essere riutilizzate in altre par- 
ti del progetto. Sarebbe quindi scomodo e ridondante 
ripetere diverse volte le stesse righe di codice, sen- 
za contare il fatto che in caso di modifica dovrem- 
mo necessariamente modificare tutti i punti nel 
progetto in cui queste righe di codice sono state 
utilizzate. Ecco che quindi ci viene in aiuto questa 
tecnica di refactoring. Vediamo il seguente sem- 



plice esempio: 

public class MyClass 



{ 



public MyClassQ 



{} 



public decimai GetAverage( int[] numbers) 



{ 



int sum = 0; 



foreach (int number in numbers) 



{ 



sum += number; 



return (decimal)sum / (decimal)numbers.Length; 



} 



> 



Questa classe contiene il metodo GetAverage che pre- 
so un array di valori int ne calcola la media arit- 
metica. Come possiamo vedere i momenti del cal- 
colo sono due: il primo quando calcoliamo la som- 
ma di tutti i valori dell' array, il secondo quando di- 
vidiamo questa somma per il numero di elemen- 
ti. E' evidente che il calcolo della somma degli ele- 
menti è una operazione di cui possiamo facilmente 
aver bisogno in altre parti della nostra applicazio- 
ne, è quindi opportuno separare questo codice dal 
metodo GetAverage affinchè possa vivere di vita 
propria ed essere riutilizzato. Per fare questo uti- 
lizziamo allora il comando Extract Method, sele- 
zionando le righe di codice relative al calcolo del- 
la somma e cliccando con il tasto destro del mou- 
se sulla selezione: 




t- \*-% i "- 

■1 RunhOiD ■ ■= 



L 




Figura 4: Voce Extract Method del menu contestuale 



Selezioniamo quindi Extract Method. Vediamo ap- 
parire una finestra di dialogo nella quale dobbia- 
mo specificare solo il nome del nuovo metodo da 
creare, nel nostro caso GetArraySum: 




http://www.ioprogrammo.it 



Dicembre 2007/ 61 ^ 



060-066:072-080 30-10-2007 16:19 Pagina 62 



SISTEMA T ■ Visual Studio ed il Refactoring 





Figura 5: Dialog del comando Extract Method 



bile sum. Fatto questo ha sostituito tutto il codice 
selezionato con la chiamata al nuovo metodo pas- 
sandogli come parametro proprio l'array di nu- 
meri da sommare. A questo punto possiamo tran- 
quillamente togliere il metodo GetArraySum dalla 
nostra classe e posizionarlo magari in una classe 
Helper da cui potrà essere richiamato molteplici 
volte da altre classi del progetto. 



-0- 



Nella stessa finestra possiamo vedere anche un'an- 
teprima di come apparirà la firma del metodo. Pre- 
muto quindi il tasto OKiì nostro codice viene mo- 
dificato in questo modo: 

public class MyClass 

J 

public MyClassQ 



{} 



public decimai GetAverage( int[] numbers) 



{ 



int sum = GetArraySum(numbers); 



return (decimal)sum / (decimal)numbers.Length; 



> 



private static int GetArraySum(int[] numbers) 



{ 



int sum = 0; 



foreach (int number in numbers) 



{ 



sum += number; 



} 



return sum; 



> 



Come possiamo vedere Visual Studio ha fatto un 
ottimo lavoro. Innanzi tutto ha creato un nuovo 
metodo GetArraySum contenente le righe di codi- 
ce da noi selezionate precedentemente, poi ha 
creato un parametro del metodo corrispondente 
alTarray di input su cui calcolare la somma ed ha in- 
serito come valore di ritorno del metodo la varia- 



ALTRE INFORMAZIONI SUL REFACTORING 



EIUCAPSULATE FIELD 

Encapsulate Field svolge anch'esso un compito 
molto utile, ovvero permette di incapsulare un 
campo pubblico all'interno di una proprietà uti- 
lizzando un campo privato come variabile di ap- 
poggio. Tutti sappiamo che non è cosa buona e giu- 
sta definire un campo pubblico all'interno di una 
classe perché questo viola il principio dell'enca- 
psulation e non ci permette di avere il controllo 
dei valori assegnati al campo. Può accadere però 
per nostra sfortuna di dover ricevere in consegna 
del codice da modificare sviluppato da qualcuno che 
non ha rispettato queste regole di buona pro- 
grammazione e quindi ci tocca rimediare. Visual 
Studio ci viene in aiuto proprio con questa tecnica 
di refactoring. È sufficiente cliccare con il tasto de- 
stro del mouse sul campo pubblico che vogliamo 
incapsulare e scegliere solo tra alcune semplici op- 
zioni all'interno della finestra di dialogo che ci ap- 
pare: 



Lì v -. . i'.iij., 



M 








Figura 6: Dialog del comando Encapsulate Field 



Vi sono diverse tecniche di 

refactoring e numerose sono le 
discussioni che ruotano attorno a 
questo tema. All'indirizzo: 
www.refactoring.com possiamo 
trovare il sito di supporto al 
testo di Martin Fowler citato 
nell'introduzione. Qui troviamo 
diverse risorse che parlano di 
refactoring nonché numerosi 
tool da scaricare per sottoporre a 
refactoring il nostro codice 



sorgente. In particolare degna di 
nota è la pagina: 

http://www.refactoring.eom/catalog/i 
ndex.html che elenca un nutrito 
numero di tecniche di 
refactoring. Informazioni di 
carattere più generale sul 
refactoring sono anche 
disponibili su Wikipedia.org 
all'indirizzo: 
http://en.wikipedia.org/wiki/Refactori 



net 



Dobbiamo nell'ordine selezionare il nome da da- 
re alla proprietà, il modo in cui deve essere effettuato 
l'aggiornamento dei riferimenti, se visualizzare 
una preview prima di apportare le modifiche, se 
effettuare le sostituzioni anche nei commenti e 
nelle stringhe di testo. La modalità di aggiorna- 
mento External permette di aggiornare tutti i ri- 
ferimenti del campo pubblico nel progetto eccet- 
to quelli della classe stessa in cui il campo è contenuto, 
mentre la modalità Ali aggiorna tutti i riferimenti 



+ 62 /Dicembre 2007 



http://www.ioprogrammo.it 



060-066:072-080 30-10-2007 16:19 Pagina 63 



Visual Studio ed il Refactoring ■ T SISTEMA 



al campo, anche quelli presenti nella stessa classe 
in cui è definito. 

Tornando al nostro esempio della classe che cal- 
cola la media, ipotizziamo di averla modificata in 
modo tale da contenere un campo che permette 
di specificare l'array sul quale calcolare la media 
piuttosto che passarlo come parametro dal relati- 
vo metodo: 



to _numbers e la sostituzione nel codice di tutti i 
riferimenti a _numbers in riferimenti alla nuova 
proprietà Numbers. Tutto questo con un paio di 
click senza contare eventuali altri riferimenti al 
campo _numbers utilizzati nel progetto che sono sta- 
ti ora automaticamente aggiornati verso la pro- 
prietà che lo ha inglobato. 




public class MyClass 



-e- 



{ 



public int[] _numbers; 



public MyClassQ 



{} 



public decimai GetAverageQ 



int sum = GetArraySum(_numbers); 



return (decimal)sum / 



(decimal)_numbers.l_ength; 



> 



Applichiamo quindi Y Encapsulate Field come spie- 
gato sopra (specificando come metodo di aggior- 
namento Ali) e premiamo OK. Vedremo il codice 
diventare: 

public class MyClass 

S 

private int[] _numbers; 

public int[] Numbers 

{ 

get { return _numbers; } 

set { _numbers = value; } 
} 



public MyClass() 
{} 



public decimai GetAverage() 

{ 
int sum = GetArraySum(Numbers); 



EXTRACT INTERFACE 

Questo comando estrae una interfaccia da una 
classe. Conosciamo rutti i pregi delle interfacce e quan- 
to queste possano risultare utili nello sviluppo 
software. Ecco quindi che nel momento in cui ci 
accorgiamo che una particolare classe presenta 
metodi, proprietà od eventi che potrebbero tran- 
quillamente essere fatti propri da altre classi, au- 
tomaticamente pensiamo di creare una interfac- 
cia da cui far derivare la classe. Grazie ad Extract 
Interface possiamo fare questo facilmente. È suffi- 
ciente posizionarsi con il cursore all'interno di una 
classe e cliccare in un punto vuoto qualsiasi con il 
tasto destro del mouse. Scegliamo dal menu Refac- 
torla voce Extract Interface e nell'ordine specifi- 
chiamo: il nome da dare all'interfaccia, il nome del 
file su disco che la conterrà, i metodi da includere 
nell'interfaccia. Riprendendo la nostra classe per il 
calcolo delle medie aritmetiche, è evidente che 



***** 




Figura 7: Dialog del comando Extract Interface 



return (decimal)sum / 



NON SOLO VISUAL STUDIO 



(decimai) Numbers. Length; 



Le modifiche apportate sono: private al posto di 
public sul campo _numbers, la creazione della nuo- 
va proprietà Numbers che espone il campo priva- 



Ecco un elenco di altri ottimi tool di 
refactoring: 

• C# Refactory 
(http://www.xt reme-simplicity. 
net/csharpref actory. htm I) 

• ReSharper 
(http://www.jetbrains.com/reshar 
per/) 

• devAdvantage 



(http://www.anticipatingminds.c 
om/content/products/devad vanta 
ge/devadvantage.aspx) 

• Refactor! for Visual Basic 2008 
(http://msdn2.microsoft.com/en- 
us/vbasic/bb693327.aspx) 

• JustCode! 
(http://www.omnicore.com/en/jus 
tcode.htm) 



http://www.ioprogrammo.it 



Dicembre 2007/ 63 ^ 



060-066:072-080 30-10-2007 16:19 Pagina 64 



SISTEMA T ■ Visual Studio ed il Refactoring 




-0- 



possiamo individuare dei metodi e proprietà ge- 
nerici che possono essere utilizzati anche per il 
calcolo di medie diverse da quella aritmetica (geo- 
metrica, quadratica, ecc.). Generiamo quindi una 
interfaccia che si chiami IAvemge e che includa la 
proprietà Numbers ed il metodo GetAverageQ- 
Dopo la pressione del tasto OK viene generato il 
file IAverage.cs contenente la seguente interfaccia: 

using System; 
namespace RefactoringTest 
{ 



interface IAverage 



{ 



decimai GetAverageQ; 



int[] Numbers { get; set; } 



} 



E la nostra classe viene fatta ereditare da IAverage: 
public class MyClass : RefactoringTest. IAverage 



{ 



private int[] _numbers; 



REORDER PARAMETERS 

Consente di riordinare i parametri di un metodo. Que- 
sta operazione può sembrare a prima vista inutile 
ma vi sono casi in cui invece si rende quasi neces- 
saria. Ipotizziamo di aver creato una serie di metodi 
in overload: 



public decima 


GetAverage( int[] numbers) 


{- } 




public decima 


GetAverage( int[] numbers, Averages 

avg) 


{- } 




public decima 


GetAverage( int[] numbers, int a, 

Averages avg) 


{- } 



MODIFICHE MULTIPROGETTO 



Le modifiche apportate dalle 
funzioni di refactoring non sono 
applicate solo nel progetto 
corrente ma sono estese anche a 
tutti i progetti correlati. Ad 
esempio se si sta sviluppando un 
Windows Form che utilizza un 
progetto Class Library ed 



effettuiamo una modifica di 
refactoring (ad esempio una 
Renarne di un metodo) all'interno 
della Class Library, saranno 
aggiornati anche tutti i 
riferimenti del progetto Windows 
Form verso quel metodo o tipo 
modificato. 



Notiamo subito che l'ultimo overload presenta il 
parametro "a" prima del parametro "avg' ma sarebbe 
più corretto che quest'ultimo mantenesse la stes- 
sa posizione rispetto agli overload precedenti (quin- 
di la seconda posizione) e che il nuovo parametro 
"a" andasse in coda agli altri. Se ci rendiamo con- 
to di questo errore dopo che oramai F overload er- 
rato è stato già utilizzato diverse volte nel codice 
diventa un bel problema modificarlo. Reorder Pa- 
rameters ci permette invece di effettuare questo 
cambiamento con semplicità. Dobbiamo soltanto 
selezionare il metodo i cui parametri desideriamo 
riordinare e dal consueto menu contestuale che 
appare cliccando con il tasto destro del mouse, se- 
lezionare dal sotto menu Refactorla voce Reorder 
Parameters. 




Figura 8: Dialog del comando Reorder Parameters 



In questa finestra scegliamo l'ordine corretto dei 
parametri (spostiamo il parametro a in coda agli 
altri) agendo su di essi con i tasti freccia sulla de- 
stra e poi premiamo il tasto OK dopo aver sele- 
zionato magari l'opzione per visualizzare una 
preview delle modifiche prima di confermarle. 
Il parametro è stato quindi correttamente spostato 
dopo tutti gli altri e altresì qualsiasi riferimento 
a questo metodo all'interno del progetto e degli 
altri collegati, è stato aggiornato per rispecchia- 
re la nuova disposizione dei parametri. 



REMOVE PARAMETERS 

Come dice il nome stesso, questo comando rimuo- 
ve un parametro da un metodo aggiornando di con- 
seguenza tutte le chiamate al metodo stesso. Sele- 
zioniamo anche in questo caso il metodo su cui agi- 
re e dal menu contestuale dei Refactor scegliamo la 
voce Remove Parameters. Viene visualizzata una fi- 
nestra di dialogo molto semplice che chiede di spe- 
cificare i parametri da rimuovere o eventualmente 
ripristinare (nello stesso momento, non dopo che 
la modifica è stata apportata). 
Come anche il messaggio di alert dice nella fine- 



* 64 /Dicembre 2007 



http://www.ioprogrammo.it 



060-066:072-080 30-10-2007 16:19 Pagina 65 



Visual Studio ed il Refactoring ■ T SISTEMA 



-0- 




Figura 9: Dialog del comando Remove Parameters 



stra di dialogo, bisogna fare attenzione nel rimuo- 
vere parametri che sono stati utilizzati all'interno 
del metodo stesso perché eliminandoli si potreb- 
bero venire a creare situazioni di errore dovute al 
fatto che il parametro viene utilizzato senza esse- 
re stato dichiarato. 



Il comando Renarne permette di rinominare un 
metodo, un namespace, un parametro od un ti- 
po, apportando la modifica all'intero progetto 
in cui è contenuto l'elemento modificato. Na- 
turalmente questo comando di refactoring non 
esegue una semplice /md e replace ma consi- 
dera il particolare elemento selezionato e quin- 
di apporta le dovute sostituzioni. Per questo 
motivo se ad esempio abbiamo un metodo che 
si chiama Connection e da qualche altra parte 
una proprietà che si chiama anch'essa Connec- 
tion (sebbene questo è preferibile evitarlo), ri- 
nominando con il comando Renarne il metodo, 
non verrà rinominata anche la proprietà ne tan- 
to meno tutti i riferimenti ad essa. Il comando 
Renarne richiede solo di specificare il nuovo no- 
me da dare all'elemento selezionato e, come 
per altri comandi di refactoring, richiede di spe- 
cificare se apportare le modifiche anche nei 
commenti e nelle stringhe testuali, oltre natu- 
ralmente alla possibilità di visualizzare una fi- 



fc±j 







■^-« 


^ 


■■■ jy M »i 









■ ■ Hi ■■ # ■■■ 



nestra di preview prima di procedere con l'o- 
perazione. Nel caso specifico della ridenomi- 
nazione di un metodo, possiamo anche sce- 
gliere se rinominare gli overload dello stesso 
oppure no. 



PROMOTE LOCALE 
VARIARLE TO 
PARAMETER 

Può accadere che dopo aver scritto un metodo 
ci si accorga che alcune variabili locali in esso de- 
finite sarebbe preferibile richiederle come pa- 
rametri nella chiamata del metodo piuttosto 
che valorizzarle all'interno dello stesso ridu- 
cendone in questo modo la flessibilità. Il co- 
mando Promote Locale Variable to Parameter 
"promuove" la variabile locale selezionata a pa- 
rametro del metodo, spostandone quindi sem- 
plicemente la definizione. Poniamo il caso di 
avere un metodo che salva una riga in un file di 
log. In prima battuta scriviamo: 

public class LogManager 

S 

public static void Writel_og(string logText) 

{ 

string logFilePath = @"C: \l_ogs\Myl_og.txt"; 
using (StreamWriter stm = File.AppendText( 

logFilePath)) 

{ 



TextWriter tw 



TextWriter.Synchronized(stm); 



tw.WriteLine(logText); 



tw.FlushQ; 



tw.Close(); 



} 




} 



Poi ci accorgiamo che sarebbe più comodo se 
il nome del file di log fosse specificato nella chia- 
mata stessa del metodo WriteLog in quanto in que- 
sto modo possiamo scrivere in file di log diffe- 
renti a seconda del punto del progetto in cui ri- 



RESOURCE REFACTORIMG TOOL 



Figura 10: Dialog del comando Renarne 



Si tratta di un add-in per Visual 
Studio 2005 che aggiunge ai già 
citati comandi di refactoring, il 
comando Extract to Resource. 
In pratica eseguendo questo 
comando su una qualsiasi 
stringa di testo specificata nel 
nostro codice, possiamo 
estrapolarla ed inserirla 



velocemente in un file di 
risorse. Al suo posto 
naturalmente sarà inserito il 
codice opportuno per 
richiamare la stringa stessa. La 
pagina principale del progetto 
ospitata su CodePlex è questa: 
http://www.codeplex.com/Resou 
rceRefactoring 



http://www.ioprogrammo.it 



Dicembre 2007/ 65 ^ 



060-066:072-080 30-10-2007 16:19 Pagina 66 



SISTEMA T ■ Visual Studio ed il Refactoring 




chiamiamo il metodo. Promuoviamo quindi la 
variabile logFilePath a parametro cliccando con 
il tasto destro del mouse sul suo nome nella de- 
finizione e dal gruppo Refactor scegliendo Renarne. 
Immediatamente vedremo la definizione della 
variabile sparire dal corpo del metodo per riap- 
parire come parametro nella firma dello stes- 
so: 



public static void Writel_og(str 


ng logText, string 

logFilePath) 


{ 




using (StreamWriter stm 


= File.AppendText( 
logFilePath)) 


{ 


TextWriter tw = 


TextWriter.Synchronized(stm); 


tw.WriteLine(logText); 


tw.Flush(); 


tw.Close(); 


} 


} 


} 



Così facendo abbiamo reso più flessibile il no- 
stro codice e più facilmente riutilizzabile. 



to lo scheletro di un metodo che avrà la stessa 
firma di quello da noi scritto. Automaticamen- 
te verranno riconosciuti i tipi dei parametri e 
di conseguenza saranno incluse nella firma le cor- 
rette definizioni. Se ad esempio senza aver an- 
cora definito il metodo GetBookDescription, 
scriviamo il seguente codice: 

string title = ""; 

string author = ""; 

decimai price = 0; 

string description = GetBookDescription 

( title, author, price); 

Selezionando Generate Method Stub dal menu 
che verrà visualizzato, Visual Studio genererà 
automaticamente il codice seguente: 

private string GetBookDescription 
(string title, string author, decimai price) 

i 

throw new Exception 
("The method or operation 

is not implemented."); 



-0- 



GENERATE 
METHOD STUB 

Per ultimo vediamo questo altrettanto como- 
do comando che ci appare in un menu dell' In- 
telliSense nel momento in cui scriviamo una 
chiamata di un metodo che non esiste ancora nel 
namespace corrente. Visual Studio automati- 
camente individua l'assenza del metodo nella clas- 
se e quindi ci mostra tramite Y IntelliSense una 
sottolineatura breve all'inizio del nome del me- 
todo, passando sulla quale ci viene visualizza- 
ta una voce di menu come quella in figura 3. 
Selezionando questa voce di menu verrà crea- 



COSA E L' AUTOMATIC CODE GENERATION 



Il menu dell'IntelliSense 
accennato nell'articolo 
relativamente al comando 
Generate Method Stub, è uno 
dei menu contestuali che 
permettono di eseguire una 
serie di azioni specifiche per un 
particolare elemento del codice 
che costituiscono la cosiddetta 
funzionalità di Automatic Code 
Generation. Questa funzionalità 
del più generico sistema 
IntelliSense, permette di inserire 



del codice li dove è prevedibile 
che venga inserito. Ecco che 
quindi abbiamo la possibilità di 
inserire automaticamente una 
using al posto del nome 
completo di un namespace, 
creare un metodo sulla base di 
una sua chiamata (Generate 
Method Stub), creare 
associazioni ai gestori di evento, 
implementare le classi base di 
tipo abstract o implementare i 
membri di una interfaccia. 



Ovvero lo scheletro del metodo GetBookDe- 
scription con i tre parametri già opportuna- 
mente tipizzati così come il valore di ritorno. 
Non ci resta quindi altro da fare che riempire il 
metodo con il codice opportuno. 



CONCLUSIONI 

Come abbiamo visto i comandi di refactoring 
che Visual Studio 2005 ci offre sono molto potenti 
ed anche facili da usare. Naturalmente questi 
comandi non sono tutti quelli possibili ed altri 
tool magari più specifici possono sicuramente 
offrire qualcosa di più. Il concetto più impor- 
tante però da capire è che produrre codice ben 
scritto, leggibile e perché no, elegante, non de- 
ve essere visto come una perdita di tempo o co- 
me una inutile sofisticazione perché i vantag- 
gi concreti sui tempi di sviluppo e sulle presta- 
zioni, nonché sulla manutenibilità non tarde- 
ranno certo ad arrivare quando sviluppare se- 
guendo queste regole sarà diventata un'abitudine. 
Non dimentichiamoci infine che rivedere il co- 
dice per migliorarlo è un processo continuo che 
va pianificato come parte integrante dello svi- 
luppo software e come tale valorizzato ed assi- 
milato. 

Gianni Malanga 



* 66 /Dicembre 2007 



http://www.ioprogrammo.it 



068-074:101-105 2-11-2007 11:52 Pagina 68 



DATABASE T H Anteprima su Microsoft Entity Framework 



MICROSOFT ENTITY 
FRAMEWORK 

LA MAGGIOR PARTE DELLE APPLICAZIONI FA USO DI DATI. LA LORO GESTIONE È SEMPRE 
STATO UNO DEI PROBLEMI FONDAMENTALI DELLA PROGRAMMAZIONE. VEDIAMO COME 
TUTTO CI VIENE RESO PIÙ SEMPLICE ATTRAVERSO I NUOVI STRUMENTI DI MICROSOFT 



^ 




□ CD U WEB 

Entity_Framework.zip 



■^ 




UMMtìMMUMm 
C#, Conoscenze base 
del .NET Framework 
3.0 e di LINQ to Entities 



Windows XP Service 
Pack 2, Windows 
Server 2003 o 
Windows Vista - .NET 
Framework 3.5 Beta 2, 
Visual Studio 2008 
(Orcas) Beta 2 o Visual 
Studio 2005 



Tempo di realizzazione 



0000 



Idati e la loro gestione rappresentano uno 
dei punti fondamentali di qualsiasi pro- 
getto software ed anche uno degli aspetti 
considerati più noiosi nello sviluppo di un'ap- 
plicazione. Gli sviluppatori devono utilizzare i 
database ma non vedono di buon occhio il 
codice ripetitivo da scrivere per persistere i 
diversi oggetti di volta in volta necessari. 
A questo scopo sono nati nel tempo diversi 
strumenti con l'intento di semplificare questo 
aspetto dello sviluppo software. Strumenti 
come i data abstraction layer, i persistence 
layer o gli object relational mapping tool tra 
cui ricordiamo a titolo di esempio il famoso 
NHibernate, vengono in aiuto dello sviluppa- 
tore per accelerare lo sviluppo e rendere più 
ottimizzato il codice. Il problema è che ognu- 
no di questi strumenti ha i suoi pregi e difetti 
e nessuno di essi può definirsi realmente la 
soluzione migliore per la gestione della persi- 
stenza dei dati. 

La scelta dello strumento più adatto da utiliz- 
zare dipende sempre dal tipo di applicazione 
e dai requisiti della stessa. Alle volte quindi gli 
stessi sviluppatori non trovando lo strumento 
adatto alla situazione specifica, preferiscono 
orientarsi verso soluzioni auto prodotte che 
sono le uniche in grado di adattarsi perfetta- 
mente al contesto applicativo anche se richie- 
dono uno sforzo implementativo di certo non 
indifferente. 

In questo scenario, quando Microsoft annun- 
ciò che avrebbe rilasciato una nuova tecnolo- 
gia denominata Entity Framework i più 
appresero la notizia con un misto di curiosità 
e scetticismo. 

La prima naturale reazione fu un confronto 
con le tecnologie esistenti, come il già citato 
NHibernate. Questo però è stato un errore 
perché in realtà YEntity Framework di 
Microsoft è una soluzione totalmente diversa 
dagli altri prodotti e nasce con finalità total- 
mente diverse. Ma quindi cos'è YEntity 
Framework' 2 . 



MICROSOFT 

ENTITY FRAMEWORK 

VEntity Framework nasce con l'intento di 
unificare il modo in cui i diversi componenti 
di un team di sviluppo software (sviluppatori, 
analisti, database administrator) concepisco- 
no la gestione della base dati, fornendo un 
linguaggio comune per raggiungere i medesi- 
mi obiettivi. Il cuore deìY Entity Framework è 
YEntity Data Model (EDM)> il nucleo che rac- 
chiude la sintassi comune utilizzata nei diver- 
si ambiti applicativi. VEDM definisce un lin- 
guaggio con il quale poter descrivere i dati 
senza doversi preoccupare di descrivere 
anche il contenitore degli stessi, ovvero il 
database. Subito sopra questo nucleo comune 
troviamo un insieme di servizi preposti alla 
manipolazione dei dati. 

Ricapitoliamo quindi cosa non è YEntity 
Framework: 

• L'EF non è solo un ORM (Object Relational 
Mapping tool) 

• L'EF non è solo un engine per la persistenza 
dei dati 

• L'EF non è solo un generatore di codice 

VEntity Framework è invece un set di servizi 
incentrati sui dati, quindi un data service 
framework. Tra questi servizi troviamo quindi 
anche la persistenza dei dati, anche servizi 
per la gestione di oggetti o per la gestione di 
viste, di query, e così via. Possiamo quindi 
definirlo come un framework che mette insie- 
me un po' tutti gli aspetti relativi alla gestione 
dei dati all'interno di un'applicazione softwa- 
re. 

Come dice il suo stesso nome, l'unità di misu- 
ra dei dati è l'Entità. Ma cos'è una entità? Per 
YEntity Framework una entità è un qualcosa 
che ha le seguenti caratteristiche: 

• È univocamente identificata tramite infor- 
mazioni contenute in se stessa 



+ 68 /Dicembre 2007 



http://www.ioprogrammo.it 



068-074:101-105 30-10-2007 16:24 Pagina 69 



Anteprima su Microsoft Entity Framework ■ T DATABASE 



-e- 



• Contiene dati di tipi definiti e specifici 

• Ha proprietà che memorizzano dati scalari 

• Ha proprietà che memorizzano le relazioni 
con altre entità 

• Non ha metodi (una entità deve descrivere, 
non eseguire) 

La struttura deìY Entity Framework vede alla 
base, sotto i noti provider diADO.NET, la base 
dati intesa come contenitore di informazioni 
e non come database in quanto sebbene il 
database sia la base dati privilegiata utilizzata 
nella stragrande maggioranza dei casi è possi- 
bile in ogni caso persistere i dati anche su file 
server o attraverso Web Service. Subito sopra i 
provider ADO.NET troviamo YEDM che 
sostanzialmente è un insieme di metadati che 
descrivono i dati utilizzati dall'applicazione 



neggiare per comprendere con più chiarezza i 
concetti affrontati. Ecco quindi una tabella 
riepilogativa dei termini e dei nomi utilizzati 
quando si parla di Entity Framework: 




Fig. 1: Architettura dell' Entity Framework 

nonché il modo in cui questi sono mappati 
sulla base dati. Inoltre YEDM fornisce dei 
meccanismi per separare nettamente il modo 
in cui le informazioni sono utilizzate dall'ap- 
plicazione e quindi dall'utente rispetto al 
modo in cui queste sono memorizzate nella 
base dati, ad esempio aggregando informa- 
zioni provenienti da differenti basi dati in una 
unica entità 



* Termine 


Descrizione ^ 


alias 


Attributo degli schemi CSDL e SSDL utilizzato nello schema 
stesso come abbreviazione del namespace completo 


association 


Definizione della relazione tra due entità 


association set 


Raggruppamento di più association appartenenti allo stesso 
tipo 


base type 


Tipo base o padre da cui altri tipi dell'Entity Data Model pos- 
sono ereditare delle proprietà. 


complexobject 


Istanza di un tipo complesso contenuta in un object context 


complextype 


Tipo complesso che rappresenta una proprietà non scalare di 
una entità e che permette di organizzare le proprietà scalari 
di una entità per gruppi 


container 


Gruppo logico di entità e associazioni {association) 


direction 


Riferita alla natura asimmetrica di alcune association, viene 
specificata negli attributi FromRole e ToRole degli elementi 
NavigationProperty o ReferentialConstraint. 


End 


Specifica una entità che partecipa ad una association 


EntityClient 


Data providerADO.NET indipendente dalla base dati che con- 
tiene le classi necessarie per l'accesso ai dati, come: Entity- 
Connection, EntityCommand e EntityDataReader. 


entity object 


Istanza di un tipo entity che vive all'interno di un Object Con- 
text 


entity set 


Contenitore logico di entità di uno stesso tipo 


Entity SQL 


Dialetto SQL indipendente dalla base dati che dialoga diretta- 
mente con lo schema concettuale (CSDL). 


facet 


Restrizione che specifica i valori ammessi per una particolare 
proprietà, come ad esempio: MaxLength, Nullable o Preci- 
sion. 


multiplicity 


Numero di entità che possono comparire su ciascuna "estre- 
mità" di una relazione. Chiamata anche cardinalità. 


navigation property 


Proprietà delle entità che permette di referenziare altre entità 
attraverso una association. 


querypath 


Query che specifica gli oggetti relazionati da recuperare 
quando viene eseguita una query su una entità 


object context 


Oggetto che rappresenta il contenitore di tutte le entità defi- 
nite nello schema concettuale e che contiene la connessione 
alla base dati sottostante fornendo inoltre diversi servizi tra 
cui ad esempio il tracciamento delle modifiche ai dati 


object query 


Query eseguita sulT Entity Data Model all'interno del contesto 
di un Object Context. Restituisce i dati sotto forma di oggetti. 


relationship 


Connessione logica tra entità 


role 


Nome dato a ciascuna End di ogni association per permetter- 
ne l'identificazione 


scalar property 


Proprietà di una entità mappata su un singolo campo dello 
Storage Schema {SSDL) 


simple type 


Tipo primitivo utilizzato per definire le proprietà delle entità 
nello schema concettuale 





LA TERMINOLOGIA 

Con Y Entity Framework è stata introdotta una 
nuova terminologia che è necessario padro- 



INSTALLAZIONE 

Per poter utilizzare l'Entity Framework è 
necessario aver installato precedentemente 
sul proprio computer il .NET Framework 3.5 



http://www.ioprogrammo.it 



Dicembre 2007/ 69 ^ 



068-074:101-105 30-10-2007 16:24 Pagina 70 



DATABASE T I Anteprima su Microsoft Entity Framework 




-^> 



IL BLOG 
DI ADO.NET 

Il blog ufficiale del 

team Microsoft di 

sviluppo di ADO.NET è 

raggiungibile 

all'indirizzo: 

http://blogs.msdn.com/ 

adonet/ 

Qui sono disponibili 

diverse informazioni 

ufficiali su ADO.NET ed 

in particolare 

sull'Entity Framework. 

Tutte le future nuove 

versioni e release 

verranno comunicate 

su questo blog prima 

che su qualunque altro 

sito. 



YEntity 
quindi in 
sufficiente 
interessati, 



Fig. 2: L' Entity Data Model 



Beta 2 (l'ultima versione 
disponibile al momento 
in cui scriviamo). Oppure 
il nuovo Visual Studio 
2008 (Orcas) Beta 2. In 
quest'ultimo caso il .NET 
Framework 3.5 è già 
installato e con esso 
anche 
Framework, 
pratica sarà 
installare, se 
solo gli ADO.NET Entity 
Framework Tools per 
essere operativi. 
L'installazione del .NET 
Framework 3.5 Beta 2 non richiede particolari 
accorgimenti. Sarà sufficiente avviare il file di 
setup, accettare i termini della licenza d'uso e 
far partire il download del Framework dal sito 
Microsoft. Questa operazione richiederà alcu- 
ni minuti a seconda della velocità della pro- 
pria connessione ad internet. Al termine del- 
l'installazione è consigliato installare gli even- 
tuali aggiornamenti e service pack dopo di 
che potremo passare all' Entity Framework. 
Avviamo il file di setup ed anche in questo 
caso dovremo solo accettare i termini della 
licenza d'uso, fatto questo, dopo alcuni 
secondi il setup terminerà e l'Entity 
Framework sarà pronto per essere utilizzato. 
Dopo questa introduzione teorica, nei prossi- 
mi paragrafi affronteremo gli aspetti più pra- 
tici dell'uso dell' Entity Framework tenendo 
sempre in mente che stiamo trattando un 
prodotto ancora in fase Beta e quindi con 
molta probabilità alcune delle cose che dire- 
mo potrebbero subire delle variazioni rispetto 
alla versione definitiva il cui rilascio è comun- 
que previsto a breve. 



ENTITY DATA MODEL 

VEntity Data Model (EDM) come abbiamo 
detto è il nucleo dell' Entity Framework in 
quanto questo permette la definizione delle 
entità, le relazioni che intercorrono tra di esse 
ed il raggruppamento delle stesse in "viste" 
logiche. 

La definizione di una entità e delle sue carat- 
teristiche è contenuta in un file XML con 
estensione xsdl e viene chiamata Conceptual 
Model, mentre il modo in cui i dati sono 
memorizzati nella base dati viene chiamato 
Storage Model ed anch'esso viene memorizza- 
to in un file XML questa volta con estensione 
.ssdl. 




Tra questi due modelli, il primo rivolto alla 
logica di business ed il secondo al data Stora- 
ge, troviamo infine lo schema di mapping che 
definisce il modo in cui le proprietà delle 
entità sono memorizzate nella base dati. 
Anche il file di mapping è un file XML che ha 
estensione .msl. 



IL CONCEPTUAL MODEL 

Un tipico file csdl che definisce il Conceptual 
Model è il seguente: 

<?xml version = "1.0" encoding = "utf-8"?> 
<Schema 

xmlns:cg = "http://schemas.microsoft.com/ado/2006/ 

04/codegeneration" 
xmlns:edm = "http://schemas.microsoft.com/ado/200 

6/04/edm" 

xmlns="http://schemas. microsoft.com/ado/2006/04/ 

edm" 
Namespace="Northwindl_ib" Alias="Self"> 

</Schema> 

All'interno di questo schema vanno inserite le 
definizioni delle entità attraverso il tag 
EntityType, di cui di seguito vediamo un 
esempio concreto: 

<EntityType Name="Employee" Key="EmployeeID"> 
<Property Name="EmployeeID" Type="Int32" 

Nullable="false" /> 

<Property Name="LoginID" Type="String" 

Nullable="false" MaxLength = "256" /> 
<Property Name="Title" Type="String" 

Nullable="false" Maxl_ength = "50" /> 
<Property Name="BirthDate" Type="DateTime" 

Nullable="false" /> 

<Property Name="HireDate" Type="DateTime" 

Nullable="false7> 



> 70 /Dicembre 2007 



http://www.ioprogrammo.it 



068-074:101-105 30-10-2007 16:24 Pagina 71 



Anteprima su Microsoft Entity Framework H T DATABASE 



-e- 



<Property Name="SalariedFlag" Type="Boolean" 
Nullable="false" /> 

<Property Name="VacationHours" Type="Intl6" 
Nullable="false" /> 

<Property Name="SickLeaveHours" Type="Intl6" 
Nullable="false" /> 

<Property Name="CurrentFlag" Type="Boolean" 
Nullable="false" /> 

<!— Altre proprietà — > 



<NavigationProperty Name="Contact" 
Relationship="Self 

.FK_Employee_Contact_ContactID" 
FromRole="Employee" ToRole="Contact" /> 



<End Role="Employee" Type="Self.Employee" 
Multiplicity="l..* 



/> 



<NavigationProperty 



Name="Managed_Employees" 



Relationship="Self 

.FK_Employee_Employee_ManagerID" 
FromRole="Employee" 

ToRole="ManagedEmployee" /> 
</EntityType> 

In questo esempio viene definita l'entità 
Employee (impiegato) avente EmployeelD 
come chiave univoca specificata con l'attribu- 
to Key. Questa entità possiede una serie di 
proprietà che la caratterizzano. Ogni pro- 
prietà ha un nome (Name), un tipo (Type) che 
viene definito con i tipi deWEDM ed un flag 
che indica se la proprietà può essere nuli 
(Nullable) oltre eventualmente ad altri attri- 
buti che definiscono meglio la proprietà come 
ad esempio MaxLength per la lunghezza mas- 
sima in caratteri. I tipi delle proprietà sono 
forniti daìYEDM il quale internamente li tra- 
duce nei corrispondenti tipi del CLR e del 
database utilizzato. 

Oltre alle proprietà, nel file csdl troviamo 
anche una serie di relazioni definite attraver- 
so il tag NavigationProperty. Nell'esempio in 
pratica l'entità Employee viene messa in rela- 
zione prima alla entità Contact e poi a se stes- 
sa tramite il campo ManagerID, attraverso l'u- 
tilizzo di una association (il cui nome è speci- 
ficato dall'attributo Relationship) ovvero 
un'associazione che definisce il rapporto par- 
ent-child delle due entità coinvolte nella rela- 
zione e la modalità con cui questa relazione 
deve essere gestita. Subito dopo la definizione 
dell'entità troveremo quindi le due associa- 
zioni richiamate dalle due Navigation- 
Property: 

<Association 

Name="FK_Employee_Contact_ContactID"> 
<End Role="Contact" Type="Self .Contact" 

Multiplicity="l..l" /> 



</Association> 



<Association 

Name="FK_Employee_Employee_ManagerID"> 
<End Role="Employee" Type="Self. Employee" 

Multiplicity="0..1" /> 
<End Role="ManagerEmployee" 

Type= "Self. Employee" Multiplicity="*" /> 
</Association> 

Nel primo caso relativo alla relazione tra 
Employee e Contact, l'associazione definisce 
una relazione di tipo uno a molti per l'entità 
Employee attraverso l'attributo Multiplicity 
impostato ad "1..*" che significa detto a paro- 
le: "un Employee può avere più Contact" (l'a- 
sterisco ha il significato di "molti"). Mentre al 
contrario un Contact può essere relazionato 
ad un solo Employee, quindi il suo attributo 
Multiplicity è impostato ad "1..1". In questo 
modo il tag Association ha definito la relazio- 
ne parent-child esistente tra le due entità 
Employee e Contact. Nel secondo caso, la rela- 
zione non coinvolge due entità distinte ma è 
rivolta su se stessa in quanto il manager 
(ovvero il responsabile) di ogni Employee è a 
sua volta un Employee. In questo particolare 
caso quindi l' association definisce un rappor- 
to molti-a-molti dove ogni Employee può 
avere uno o più Manager e viceversa. 



LO STORAGE MODEL 

I file ssdl contenenti lo Storage Model sostan- 
zialmente descrivono la base dati utilizzata 
dall'applicazione che fa uso de\Y Entity Data 
Model. Anche in questo file troviamo le defini- 
zioni delle entità e delle associazioni delle 
stesse tra di loro ed il modo in cui vengono 
definite è molto simile a quello dei file csdl, la 
differenza sta nei tipi utilizzati che mentre nei 
file csdl sono quelli de\Y Entity Data Model, nei 
file ssdl sono quelli specifici del database uti- 
lizzato dall'applicazione. 
La prima parte di un file ssdl contiene, come 
per i file csdl, la definizione del namespace: 

<?xml version="1.0" encoding = "utf-8"?> 
<Schema Namespace="NorthwindModel" Alias="Self" 
xmlns="http://schemas. microsoft.com/ado/2006/04/ 

edm/ssdl"> 

Successivamente troviamo quindi le defini- 




ADO.NET 
ENTITY 
FRAMEWORK 
TOOLS 

Insieme all'Entity 
Framework se si 
utilizza Visual Studio 
2008 Beta 2 può essere 
interessante anche 
installare il pacchetto 
ADO.Net Entity 
Framework Tools Aug 
07 Community 
Technology Preview 
per aggiungere al 
designer di Visual 
Studio il supporto 
dell 'Entity Framework 
e poter così lavorare in 
maniera visuale sul 
codice. 



http://www.ioprogrammo.it 



Dicembre 2007/ 71 ^ 



068-074:101-105 30-10-2007 16:24 Pagina 72 



DATABASE T I Anteprima su Microsoft Entity Framework 



■€+ 




EMTITYSQL 

Il nuovo linguaggio 

SQL dedicato all'Entity 

Framework e 

denominato EntitySQL 

è stato progettato 

specificatamente per 

trattare oggetti ed 

entità a differenza del 

linguaggio SQL classico 

che invece permette di 

accedere e manipolare 

dati relazionali 

provenienti da 

database. Per una 

trattazione più 

approfondita di questo 

nuovo linguaggio è 

possibile consultare il 

seguente post del blog 

ufficiale di ADO.NET: 

http://blogs.msdn.com/ad 

onet/archive/2007/05/30/e 

ntitysql.aspx 



zioni delle entità e delle associazioni: 



<EntityType Name="Employee" Key="EmployeeID"> 
<Property Name="EmployeeID" Type="int" 

Nullable="false" /> 

<Property Name="LoginID" Type="varchar" 

Nullable="false" MaxLength="256" /> 
<Property Name="Title" Type="varchar" 

Nullable="false" MaxLength="50" /> 

</EntityType> 

<EntityContainer Name="dbo"> 
<EntitySet Name="Employee" 
EntityType="Self.Employee" Schema = "dbo" 

Tables="Employee" /> 
<AssociationSet 

Name="FK_Employee_Contact_ContactID" 

Association = "Self.FK_Employee_Contact_ContactID"> 

<End Role="Contact" EntitySet="Employee" 

/_>_ 

<End Role="Employee" 

EntitySet="Employee" /> 
</AssociationSet> 
<AssociationSet 

Name="FK_Employee_Employee_ManagerID" 
Association = "Self.FK_Employee_Employee_ManagerI 

D"> 
<End Role="Employee" 

EntitySet="Employee" /> 
<End Role="ManagerEmployee" 

EntitySet="Employee" /> 
</AssociationSet> 
</EntityContainer> 



Come possiamo notare i due schemi sono 
molto simili ma balzano subito agli occhi i 
diversi tipi utilizzati per le proprietà dell'en- 
tità. Infatti se nel file csdl avevamo i tipi Int32, 
String, ecc, nel file ssdl troviamo invece int, 
varchar, ecc, che sono specifici della base dati 
considerata, in questo caso un database di 
SQL Server. 



IL MAPPIMG 

Infine abbiamo i file di mapping con estensio- 
ne .msl che mettono in relazione il Conceptual 
Model con lo Storage Model e si presentano 
come segue: 

<?xml version = "1.0" encoding = "utf-8"?> 
<Mapping Space="C-S" xmlns="urn:schemas- 

microsoft-com: Windows: Storage: mapping :CS"> 
<EntityContainerMapping 

CdmEntityContainer="Employee" 
StorageEntityContainer="NorthwindEmployee"> 



</EntityContainerMapping> 



</Mapping> 

Con il tag EntityContainerMapping e i due 
attributi CdmEntityContainer e Storage- 
EntityContainer mettiamo quindi in relazio- 
ne la definizione concettuale dell'entità 
Employee (definita con il file csdl) con la defi- 
nizione fisica della stessa Employee nel data- 
base Northwind (definita con il file ssdl). Nel 
file di mapping, all'interno del tag Entity- 
ContainerMapping possiamo trovare poi una 
serie di tag EntitySetMapping che mettono in 
relazione con le tabelle del database eventua- 
li Entity Set, ovvero dei raggruppamenti di 
entità mappate sulla stessa 

tabella. Fortunatamente con Visual Studio 
2008 Beta 2 anche nelle versioni Express gra- 
tuite, non è necessario conoscere le specifiche 
di questi tre file XML di definizione in quanto 
insieme all' Entity Framework viene rilasciato 
anche un tool denominato EdmGen.exe 
(Entity Data Model Generator) che crea auto- 
maticamente per noi questi tre file a partire 
da un database esistente. Volendo quindi uti- 
lizzare per la nostra applicazione il famoso 
database Northwind come abbiamo fatto sino 
ad ora, sarà sufficiente eseguire dal prompt 
dei comandi: 



LVMTOHIIin 







QflXCTai 










Fig. 3: Panoramica riepilogativa dell' Entity Framework 



> 72 /Dicembre 2007 



http://www.ioprogrammo.it 



068-074:101-105 30-10-2007 16:24 Pagina 73 



Anteprima su Microsoft Entity Framework H T DATABASE 



edmgen.exe /provider: System. Data. SqlClient 



/connectingString = "Server=.;database= northwind ;int 



egrated security=sspi" 



-0- 



/mode:FullGeneration 



/project: Northwind 

Al termine dell'elaborazione, EdmGen.exe 
avrà generato i tre file menzionati sopra, 
ovvero i file Northwind.ssdl, Northwind. csdl e 
Northwind. msl che potranno essere inclusi 
nel progetto dell'applicazione ed utilizzati 
tramite V Entity Framework. Oppure dopo aver 
installato gli ADO.Net Entity Framework Tools 
ancora più semplicemente potremo utilizzare 
per questa operazione il designer di Visual 
Studio e l'item template per la creazione di un 
nuovo Entity Data Model con il relativo 
wizard. Ecco uno schema riepilogativo delle 
relazioni che intercorrono tra i diversi compo- 
nenti dell' Entity Framework: 



CONNECTION STRING 

Affinché YEntity Framework possa dialogare 
con il database ed utilizzarlo quale contenito- 
re per i dati dell'applicazione è necessario 
creare una Entity Connection, ovvero una con- 
nection string particolare che utilizza come 
data provider la dll System. Data. Entity Client: 

<connectionStrings> 

<add name="Northwind" 

connectionString = 'Metadata = .; 

Provider= System. Data. SqlClient; 
Provider Connection 

String = "server=servername; 

database= Northwind ;Integrated 

Security=true; 

Connection 
Timeout=10;multipleactiveresultsets=true"' 
providerl\lame="System.Data.EntityClient7> 
</connectionStrings> 

Notiamo in particolare l'attributo Metadata 
attraverso il quale viene specificata la cartella 
nella quale sono presenti i tre file dei metada- 
ti che abbiamo descritto precedentemente, 
ovvero il file .csdl, .ssdl e .msl. Con il "." dicia- 
mo che i file dei metadati sono presenti nella 
stessa cartella dell'eseguibile. Se così non 
fosse dovremmo specificare il percorso com- 
pleto in cui sono stati salvati i file dei metada- 
ti. 



ESEGUIRE QUERY 
SULLE ENTITÀ 

Vediamo ora, dopo aver definito i metadati, 
come possiamo accedere da codice alle entità 
per interrogarle o modificarle. Innanzi tutto 
dobbiamo inserire alcune using nella nostra 
classe per accedere più agevolmente ai diver- 
si oggetti di cui faremo uso. Quindi aggiungia- 
mo oltre ai classici namespace anche i 
seguenti: 



using System. Data; 


using System. Data. Metadata. Edm; 


using System. Data. Common; 


using System. Data. Objects; 


using System. Data. EntityClient; 


using System. Linq; 


using System. Xml. Linq; 


using NorthwindLib; 



e quindi la nostra classe: 



public abstract partial class Employee 

_i 

public ObjectQuery<Customer> AllCustomers 

{ 

get 



NorthwindEntities context = new 

NorthwindEntities(); 

var query = from e in context. Customers 
where c.Orders.Any(o => 
o.EmployeelD == this.EmployeelD) 
select e; 

return query as ObjectQuery<Customer>; 



> 



Alla classe Employee già esistente perché defi- 
nita dall' Entity Data Model, aggiungiamo una 
proprietà che ci restituisce tutti i clienti del 
dipendente il cui EmployeelD corrisponde a 
quello specificato nella omonima proprietà 
EmployeelD della classe stessa. Quello che 
viene fatto è innanzi tutto creare una classe 
parziale in modo da poter aggiungere una 
nuova proprietà e poi viene creato un oggetto 
di contesto (context) utilizzando la classe 
NorthwindEntities che espone tutte le entità 
definite nel nostro modello concettuale. Nello 
specifico di questo esempio, creiamo una 
query utilizzando LINQ to Entities, dove dicia- 
mo di recuperare tutte le entità Customer 
aventi degli ordini la cui proprietà 
EmployeelD corrisponde all' EmployeelD cor- 




REFERENZIARE 
DLL NEI 
PROGETTI 

In Visual Studio per 
referenziare un 
assembly in un 
progetto è sufficiente 
cliccare con il tasto 
destro del mouse sul 
nome del progetto, 
scegliere la voce Add 
Reference... , cliccare 
sul tab Browse e 
selezionare dal disco 
rigido la DLL che 
s'intende referenziare 
nel progetto. 



ADO.NET 
SAMPLES 

All'indirizzo: 
http://www.codeplex.com 
/adonetsamples/ 
è disponibile un 
nutrito pacchetto di 
esempi incentrati 
sull 'Entity Framework 
e con i quali è possibile 
impratichirsi 
ulteriormente su 
questa tecnologia. 



http://www.ioprogrammo.it 



Dicembre 2007/ 73 ^ 



068-074:101-105 30-10-2007 16:24 Pagina 74 



DATABASE T I Anteprima su Microsoft Entity Framework 



-e- 




rente. Quindi restituiamo il risultato della 
query sotto forma di oggetto ObjectQuery che 
contiene l'elenco delle entità Customer richie- 
ste. Alla query LINQ è possibile sostituire il 
nuovo linguaggio eSQL (Entity SQL) sviluppa- 
to appositamente per le interrogazioni di dati 
all'interno de\Y Entity Data Model. Ecco come 
si presenterebbe la proprietà AUCustomers 
con l'utilizzo di eSQL: 

public ObjectQuery<Customer> AUCustomers 

S 

get 



NorthwindEntities context 



new 
NorthwindEntities(); 




L'AUTORE 



Gianni Malanga 

Lavora da più di 10 

anni con tecnologie 

Microsoft in 

particolare nel campo 

dello sviluppo Web. 

Sviluppa in .NET ormai 

da alcuni anni e ha 

svolto diverse docenze 

per corsi di formazione 

professionali. Dopo 

aver lavorato alle 

dipendenze di 

importanti realtà 

locali, attualmente ha 

intrapreso la libera 

professione 

costituendo la ditta 

individuale Kaone 

Consulting che si 

occupa di consulenza 

informatica per PMI su 

tutto il territorio 

nazionale. Gli si può 

scrivere all'indirizzo 



ObjectQuery<Customer> query = 

context. CreateQuery<Customer>( 
"SELECT VALUE e FROM Orders AS e WHERE 

c.EmployeelD = @EmployeeID", 
new ObjectParameter("EmployeeID" 

this.EmployeelD)); 

return query as ObjectQuery <Customer>; 




> 



Infine per recuperare gli oggetti restituiti dalla 
query è sufficiente ciclare all'interno dell'og- 
getto ObjectQuery: 

foreach (Customer e in query) 

S 

Response.Write(c.CompanyName); 

} 

Aggiungere una nuova entità nella base dati è 
altrettanto semplice: 

Category newCat = new Category(); 
newCat.CategoryName = "Nuova categoria"; 
context. AddToCategories(newCat); 
context. SaveChangesQ; 



ADO.NET ENTITY FRAMEWORK BETA 2 



L" Entity Framework Beta 2 è 

disponibile doppia versione per 

processori a 32 bit (EFSetup- 

x86.exe) e a 64 bit (EFSetup- 

x64.exe) al seguente indirizzo del 

sito Microsoft: 

http://www.microsoft.com/downloads/ 

details.aspx?FamilylD=f1adc5d1-a42e- 

40a6-a68c 

a42ee1 1 186f7&displaylang=en 



Tra i requisiti dell 'Entity 
Framework vi è la presenza sulla 
macchina del .NET Framework 3.5 
Beta 2 che è possibile recuperare 
da questo indirizzo: 

http://www.microsoft.com/downloads/ 



details.aspx?FamilylD=d2f74873-c796- 

4e60-91c8- 

f0ef809b09ee&DisplayLang=en 



int newCatlD = newCat.CategorylD; 

In questo caso aggiungiamo una nuova cate- 
goria nella tabella delle categorie del database 
Northwind. Come vediamo è sufficiente crea- 
re un oggetto di tipo Category, valorizzarlo 
con i dati che ci interessano e quindi richia- 
mare il metodo AddToCategories del contesto 



féln wm 



!.. 





*U 






+ -I^»ÌJW1 


* 




tW^ 


émLmi 






* 


♦■■tì^" 






IH 














. iWr ■*- 




4 


Atfl^lABI 




■ 





Fig. 4: Metodi dell'oggetto di contesto 

per passare il nuovo oggetto appena creato. 
Subito dopo richiamiamo il metodo 
SaveChanges per persistere effettivamente le 
informazioni, quindi possiamo leggere la pro- 
prietà CategorylD della nuova entità aggiunta 
per leggerne l'ID. Come vediamo dall'immagi- 
ne seguente, oltre agli specifici metodi per 
l'aggiunta di ciascuna entità, vi è anche il 
metodo generico AddObject che permette di 
aggiungere una qualsiasi entità tra quelle pre- 
viste dal Conceptual Model. 



CONCLUSIONI 

Gestire correttamente i dati nelle applicazioni 
software è importante in quanto i dati rappre- 
sentano il fulcro attorno a cui ruota tutta la 
logica applicativa. Saper utilizzare quindi 
strumenti che facilitano la gestione degli stes- 
si e rendono anche più rapido lo sviluppo è 
importante per produrre software di qualità. 
E' evidente che al termine della fase Beta 
dell' Entity Framework gli strumenti messi a 
disposizione saranno più maturi e permette- 
ranno allora realmente di creare delle solide 
basi per lo sviluppo di tutte quelle applicazio- 
ni che si basano fortemente sui dati e sulla 
loro manipolazione. Non ci resta quindi che 
attendere il rilascio della versione definitiva 
de — 11' Entity Framework per cominciare ad 
utilizzarlo al pieno delle sue potenzialità. 

Gianni Malanga 



* 74 /Dicembre 2007 



http://www.ioprogrammo.it 



076-077:082-083 30-10-2007 16:14 Pagina 76 



TIPS&TRICKS T I Una raccolta di trucchi da tenere a portata di... mouse 



I trucchi del mestiere 

Tips & TVicks 

Questa rubrica raccoglie trucchi e piccoli pezzi di codice, frutto dell'esperienza di chi programma, che solitamente non 
trovano posto nei manuali. Alcuni di essi sono proposti dalla redazione, altri provengono da una ricerca su Internet, altri 
ancora ci giungono dai lettori. Chi volesse contribuire, potrà inviare i suoi Tips&Tricks preferiti. Una volta selezionati, 
saranno pubblicati nella rubrica. Il codice completo dei tips è presente nel CD allegato nella directory \tips\o sul Web 
all'indirizzo: cdrom.ioprogrammo.it. 



^ 




COME POSSO 

IMPLEMENTARE IL BUBBLE 
SORT 



#include <iostream> 



using namespace std; 



int compare(int, int); 



void sort(i nt[], const int); 



void swap(int *, int *); 



int compare(int x, int y) 



{ 



return(x > y); 



> 



void swap(int *x, int *y) 



{ 



int temp; 



temp 



*y = temp; 



void sort(int table[], const int n) 



{ 



for(int i = 0; i < n; i++) 



{ 



for(int j = 0; j < n-1; j++) 



{ 



if(compare(table[j], table[j+l])) 



swap(&table[j], &table[j+l]); 



int tab[3]; 



int main() 



cout << "Input numbers: \n"; 



for (int i = 0; i < 3; i++) 



cin >> tab[i]; 


} 




cout << 


"Before sorting: "; 


for (int i 


= 0; i < 3; i ++) 


{ 


cout 


<< tab[i] << " "; 


} 




cout << 


"\nAfter sorting: "; 


sort(tab, 


3); 


for(int i 


= 0; i < 3; i ++) 


{ 


cout 


<< tab[i] << " "; 


} 


return 0; 


} 



m 



JAVA 



COME POSSO CONVERTIRE 
UN NUMERO DA ARABO IN 
ROMANO 



public String deka2r( int nr ) 


{ 


String deka2r = ""; 


try 


{ 


if( nr >= 889 ) 


{ 


deka2r = "M" + deka2r( (nr 


- 1000) ); 


} 


else if( nr >= 389 ) 


{ 


deka2r = "D" + deka2r( (nr - 


500) ); 


} 


else if( nr >= 89 ) 


{ 


deka2r = "C" + deka2r( (nr - 


100) ); 


} 



* 76 /Dicembre 2007 



http://www.ioprogrammo.it 



076-077:082-083 30-10-2007 16:14 Pagina 77 



-0- 



Una raccolta di trucchi da tenere a portata di... mouse ■ T TIPS&TRICKS 



else if( nr > = 


39 ) 




{ 


deka2r = "L' 


+ deka2r( (nr - 


50)); 


} 


else if( nr > = 


9) 




{ 


deka2r = "X' 


+ deka2r( (nr - 


10)); 


} 


else if( nr > = 


4) 




{ 


deka2r = "V 


+ deka2r( (nr - 


5)); 


} 


else if( nr > = 


1) 




{ 


deka2r = "I" 


+ deka2r( (nr - 


i)); 


} 


else if( nr < = 


-889 ) 




{ 


deka2r = "M 


' + deka2r( nr 4 


1000 );} 


else if( nr < = 


-389 ) 




{ deka2r = "D 


" + deka2r( nr + 500 ) } 


else if( nr < = 


-89 ) 




{ 


deka2r = "C 


+ deka2r( nr + 


100 ); 


} 


else if( nr < = 


-39 ) 




{ 


deka2r = "L' 


+ deka2r( nr + 


50 ); 


} 


else if( nr < = 


-9) 




{ 


deka2r = "X' 


+ deka2r( nr + 


10); 


} 


else if( nr < = 


-4) 




{ 


deka2r = "V 


+ deka2r( nr + 


5); 


} 


else if( nr < = 


-1 ) 




{ 


deka2r = "I" 


+ deka2r( nr + 


i ); 


} 


} 


catch(Exception 


_e_) { Err.set(_ 


e_,"deka2r"); } 


return deka2r; 


} 



Long) As Long 



<summary> 



' Function to check and see if an instance of the application is already 

open 



</summary> 



<param name="sApp">Name of the application</param> 



<returns>True/False</returns> 



<remarksx/remarks> 



Public Shared Function IsAlreadyOpen(ByVal sApp As String) AsBoolean 
'Check running processes to see if application is already running 

Dim pProcess As Processo = 

System. Diagnostics.Process.GetProcessesByName(sApp) 
If pProcess. Length > 1 Then 'If > 1 then its already running 

Return True 

Else 'Not running 

Return False 

End If 

End Function 



<summary> 



Procedure to activate current instance 



if user is trying to open a 2nd instance of application 



</summary> 



<remarksx/remarks> 



Public Shared Sub ActivatePrevInstanceQ 



Dim IngPrevHndl As Long 



Dim IngResult As Long 



Dim oProcess As New Process 'Variable to hold individuai Process 
IngPrevHndl = oProcess. MainWindowHandle.ToInt32() 



If IngPrevHndl = Then 



Exit Sub 'if No previous instance found exit the the procedure 



Else 



"If found 



IngResult = Openlcon(lngPrevHndl) 'Restore the program. 
IngResult = SetForegroundWindow(lngPrevHndl) 'Activate the 

application. 



End 'End the current instance of the application. 
End If 



End Sub 



'Sample usage: 






VB.NET 



'Cali from main form of you application in the Form_Load event 



If Classi. IsAlreadyOpen(Application.ProductName) Then 



COME POSSO EVITARE 
DI APRIRE DUE ISTANZE 
DELLA STESSA APPLICAZIONE? 



'Windows API 



Declare Function Openlcon Lib "user32" (ByVal hwnd As Long) As Long 
Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As 



MessageBox.Show("You cannot have 2 instances of " & _ 
Application. ProductName & " running, closing application", &_ 
"Error: Application already open", &_ 
MessageBoxButtons.OK, MessageBoxIcon. Error) 
Classl.ActivatePrevInstanceQ 



End If 



http://www.ioprogrammo.it 



Dicembre 2007/ 77 ^ 



080-085:072-080 30-10-2007 17:03 Pagina 80 



SISTEMA T ■ Una form per il login in Flex 



VAUDARE L'INPUT 
USANDO FLEX 

AFFRONTIAMO UNO DEI PROBLEMI BASILARI PER OGNI PROGRAMMATORE: CONTROLLARE 
LA CORRETTA IMMISSIONE DEI DATI. COME ESEMPIO APPLICATIVO UTILIZZEREMO UNA 
FORM FLASH PER L'AUTENTICAZIONE DEGLI UTENTI 



^ 





CD G WEB 

Flex.Zip 



^jjmmmMm 




I Basi di XML, 
ActionScript 



ff 



Flex Builder, Flex SDK 



Tempo di realizzazione 



00OO 



Nella puntata precedente ci siamo lascia- 
ti con una applicazione che simulava la 
procedura di login al "Music Shop". In- 
fatti qualunque cosa inserissimo come user e 
password , l'applicazione rispondeva con una 
semplice finestra di messaggio. Vediamo allora 
come possiamo migliorare la nostra applicazio- 
ne, sia da un punto di vista funzionale che ar- 
chitetturale. 



VALIDAZIOIME 
DELL'INPUT 

Partiamo dal punto di vista funzionale. Una pri- 
ma cosa che banalmente l'applicazione, o me- 
glio, nello specifico, la maschera di login deve 
fare è controllare che i campi relativi alla users 
e/o alla password non siano vuoti quando si pre- 
me il pulsante "Conferma". Come si può facil- 
mente immaginare, non è conveniente far effet- 
tuare questi controlli al codice lato server, in 
quanto sprecheremmo un round-trip per veri- 
ficare che magari il campo è vuoto. Come pos- 
siamo controllare queste informazioni prima 
dell'invio ? Una soluzione banale potrebbe es- 
sere quella di effettuare le verifiche nel metodo 
associato al click del pulsante. Questa soluzio- 
ne decisamente funziona, ma possiamo fare di me- 
glio utilizzando una feature del Flex SDK, cioè i 
validators. 

Il Flex SDK mette a disposizione una serie di clas- 
si di validazione, dette appunto validators, per 
effettuare la convalida di informazioni inserite 
dall'utente. Si va dalla validazione di una infor- 
mazione obbligatoria, alla validazione di un in- 
dirizzo e-mail piuttosto che di un valore nume- 
rico o di una data. Alcuni validators possono ri- 
sultare non appropriati se applicati in un con- 
testo prettamente nazionale, ad esempio 1' SSN 
validator è rivolto a validare il codice sanitario ame- 
ricano. Comunque, indipendentemente da que- 
sto, vi è sempre la possibilità di derivare una clas- 
se customizzata ed implementare un meccanismo 



di validazione che si adatta maggiormente alle 
esigenze della applicazione che si sta svilup- 
pando. Iniziamo con il vedere come validare sem- 
plicemente le due informazioni immesse nei 
campi relativi allo user ed alla password. Per de- 
finire un validator utilizzando la sintassi mxml 
utilizziamo il tag: 

<mx: Validator id = "reqValid" required = "true" 
source="{txtUserName>" 
property="text" 
invalid="m_ml.handleValidation(event)" /> 

Oltre ad indicare l'id dell'elemento mxml, va indi- 
cato il controllo da validare e la sua specifica pro- 
prietà da verificare. Nel nostro caso stiamo vali- 
dando lo username, cioè stiamo validando ciò che 
si trova nel campo text di un controllo Textlnput Quin- 
di utilizzando le proprietà del controllo Validator, 
source e property, indichiamo nello specifico cosa 
sottoporre a validazione. 

Nell'esempio abbiamo anche utilizzato l'evento 
invalid. Questa indica una azione da intraprende- 
re in seguito al fallimento della validazione. Per 
contro esiste anche un evento valid a cui associa- 
re operazioni necessarie in caso di una validazio- 
ne riuscita. Normalmente Flex esegue la valida- 
zione quando viene sollevato l'evento valueCom- 
mit di un controllo. Ciò avviene ad esempio quan- 
do il controllo perde il focus, cioè l'utente si sposta 
dal controllo in questione su di un altro, oppure se 
la proprietà osservata viene modificata da codice. 
E' possibile modificare questo comportamento 
standard utilizzando la proprietà trigger e l'even- 
to triggerEvent. Così facendo possiamo indicare 
che la validazione deve avere luogo quando l'e- 
vento indicato da triggerEvent del controllo indicato 
da trigger viene sollevato. 
Ad esempio: 

<mx:Validator id = "reqValid" required = "true" 
source="{txtUserName>" 
property = "text" 
invalid ="m_ml.handleValidation(event)" 



* 80 /Dicembre 2007 



http://www.ioprogrammo.it 



080-085:072-080 30-10-2007 17:03 Pagina 81 



Una forni per il login in Flex ■ T SISTEMA 



trigger="{btnConfirm}" 



triggerEvent="click7> 

In questo modo abbiamo indicato che la valida- 
zione deve avere luogo in seguito all'evento click del 
controllo con id btnConfirm, cioè il nostro pul- 
sante "Conferma". 
Riassumendo, il seguente codice: 



PERSONALIZZARE 
LA VALIDAZIOME 

Nel caso in cui nessuno dei validators messi a no- 
stra disposizione dal Flex SDK sia adatto alla si- 
tuazione specifica, possiamo scriverne uno cu- 
stom, in maniera molto semplice. Consideriamo 
il caso in cui dobbiamo verificare che la password, 
ad esempio, rispetti una serie di precise regole: 




<mx:ControlBar 

horizontalAlign = "center" > 



-e- 



<mx:Button 
label = "Conferma" id="btnConfirm" click=""/> 
<mx:Button 
label = "Annulla" id = "btnCancel" comerRadius="5"/> 



</mx:ControlBar> 



<mx:Validator id = "reqValid" required = "true" 

source="{txtUserName>" property="text" 
invalid = "m_ml.handleValidation(event)" 
trigger="{btnConfirm>" triggerEvent= "click" 
valid="SendData()" /> 



permette di eseguire la validazione sulla pressione 
del pulsante "Conferma" e di ottenere una segna- 
lazione di errore per l'utente come indicato in Fi- 
gura 1. 




Figura 1: Segnalazione dell'errore da parte del validator. 



È chiaramente possibile modificare il testo del mes- 
saggio, altrimenti un pò laconico, in modo da indicare, 
all'utente, il problema con maggiore precisione. 
Per far ciò, basta utilizzare la proprietà required- 
FieldError. Per poter effettuare una convalida più 
fine, nel caso di una stringa di testo, possiamo usa- 
re il tag <mx:StringValidator>. Con questo tipo di 
validator, potremo ad esempio, indicare una lun- 
ghezza minima e massima per la stringa e i relati- 
vi messaggi da visualizzare all'utente in caso di fal- 
limento della verifica. 



• Non contenga lo username; 

• Contenga almeno un valore maiuscolo; 

• Contenha almeno un valore numerico; 

In questo caso, non avendo un validator precon- 
fezionato possiamo svilupparlo noi semplicemente 
derivandolo dalla classe Validator, vedi figura 2. 




Figura 2: Creaimo la nostra classe di validazione derivan- 
dola da mx.validators. 



Il codice completo del validator custom lo trovate 
nel progetto allegato, nel file PasswordValidator, 
nella cartella "BizWalidators". La cosa da sottoli- 
neare è che tutto quello che dobbiamo fare per de- 
finire il nostro validator è effettuare solo l'override 
del metodo doValidation. Infatti esso sarà poi ri- 
chiamato dal framework durante il processo di va- 
lidazione. 

Il validator cosi realizzato potrà essere utilizzato 
sia come tag mxml che richiamato via codice. Per 
utilizzarlo come tag mxml, è necessario specifica- 
re nel tag mxiApplication il namespace nel quale è 
dichiarata la classe del validator stesso. 
Quindi inserendo nel tag Application: 

xmlns:BizVldts="Biz. Validators.*" 

indichiamo con la keyword BizVldts un alias per il 
namespace Biz. Validators e possiamo cosi riferir- 
ci al validator custom come se fosse un normale 
tag mxml: 

< BizVldts: PasswordValidator id = "pwdValid" 
source="{txtPassword>" 
property="text" 



COME 
INIZIARE 

Per cominciare subito 
a lavorare, copiate il 
codice allegato 
all'articolo sul vostro 
HD. Poi aprite il Flex 
Builder, quindi dal 
menu File I New, 
scegliete Import e 
poi la voce Existing 
Projects into 
Workspace. Indicate 
la cartella che 
contiene il file .mxml 
principale del 
progetto, ed il gioco 
è fatto. 



http://www.ioprogrammo.it 



Dicembre 2007/ 81 ^ 



080-085:072-080 30-10-2007 17:03 Pagina 82 



SISTEMA T ■ Una forni per il login in Flex 




required = "true" 



SCARICARE 
FLEXBUILDER 

Il Flex Builder ed il 

Flex SDK possono 

essere scaricati dal 

sito della Adobe 

all'indirizzo: 

http://www.adobe.co 

m/products/flex/. 

Chiaramente, 

l'installazione del 

Flex Builder include 

quella del Flex SDK. 



-0- 



UserName="{txtUserName.text}"/> 



VALIDAZIOME MULTIPLA 

Dato che il nostro processo di validazione si 
compone in effetti di due validazioni, la prima 
per lo username e la seconda per la password, 
e se concluso con successo, deve inviare que- 
ste informazioni al server per l'autenticazione, 
possiamo riorganizzare il nostro codice in que- 
sto modo: 

<mx:Button label = "Conferma" id = "btnConfirm" 

click="ValidateForm()" /> 

Il pulsante conferma richiama un metodo Vali- 
dateForm in cui eseguire i metodi validate dei sin- 
goli validators: 



private function 

ValidateForm():void 


{ 


result = 

userValid.validate(); 


if( result. type = = 
ValidationResultEvent.INVALID) return; 




result = 

pwdValid.validate(); 


if( result. type = = 
ValidationResultEvent.INVALID) return; 




SendData(); 


} 



Cosi, solo quando entrambi i validators sono 
eseguiti con successo, verrà richiamato il me- 
todo SendData per l'invio dei dati al server. 
Questo è necessario in quanto se, come visto 
prima, indichiamo per ciascun validator le infor- 
mazioni di trigger ed impostiamo la proprietà 
valid, alla prima validazione positiva il meto- 
do specificato nella proprietà valid sarà ese- 
guito, mentre nel frattempo si procede con la 
seconda validazione. Questo può rendere am- 
bigua l'operazione di validazione e generare 
uno spreco di risorse in quanto sarà avviata la co- 
municazione con il server durante una fase in- 
termedia della validazione. 



primo avvio. Per realizzare un file di configurazio- 
ne per il nostro Music Shop possiamo pensare ad 
un piccolo file .xml contenente le informazioni ne- 
cessarie allo start-up dell'applicazione. Ad esem- 
pio, l'immagine di sfondo e gli uri per l'autentica- 
zione, in modo da non dover scrivere queste infor- 
mazioni nel codice e poterle modificare con un 
semplice editor di testo. 

Il nostro file di configurazione sarà molto sempli- 
ce, ma ci permetterà comunque di introdurci al 
supporto dedicato dal Flex SDK alla gestione del- 
l'XML. Nel file di configurazione troviamo solo le se- 
guenti informazioni: 

<MusicShop> 

<LoginUrl url = " 
http://localhost/MusicShop/Login.aspx" /> 

<BackgroundImage> 
F:\Progetti\Articoli\Flex2\Immagini\CDWall.jpg 



</BackgroundImage> 



</MusicShop> 

Strutturato in questa maniera, il file .xml pre- 
senta una informazione, l'uri della pagina ser- 
ver per l'autenticazione, sotto forma di attribu- 
to, mentre il nome dell'immagine di sfondo è co- 
stituita da un nodo. Vediamo come poterlo ana- 
lizzare. 

Nell'ottica di organizzare al meglio il codice, pre- 
pariamo una nuova classe chiamata "Config" che 
deriva dalla classe EventDispatcher. La classe ba- 
se EventDispatcher consente all'oggetto deriva- 
to di accedere a tutta una serie di funzionalità 
legate al modello degli eventi del Flex Framework. 
Tralasciando i particolari della gestione degli 
eventi su cui si soffermeremo in seguito, quello 
che ci interessa al momento della classe Config 
è la sua capacità di leggere il file .xml di confi- 
gurazione ed accedere alle sue parti. 
Nel metodo Load abbiamo definito il meccanismo 
di lettura del file. Infatti mediante i due oggetti URL- 
Request ed URLLoader possiamo caricare una 
sorgente dati esterna, nello specifico un file .xml. 
La classe URLRequest permette di catturare le 
informazioni presenti in uno stream HTTP de- 
finito verso l'uri che specifichiamo nel costruttore 
della classe. Quindi combinando questa con la clas- 
se URLLoader, che si occupa dell'accesso all'uri 
prima specificato, è possibile effettuare il cari- 
camento di dati da una qualsiasi sorgente ester- 
na, nel nostro caso un file .xml. 



CONFIGURAZIONE 
DELL'APPLICAZIONE 

Generalmente una applicazione ha bisogno di una 
serie di informazioni con cui configurarsi sin dal 



private var 



myLoader: URLLoader; 



var XML_URL:String = 
"MusicShop.xml?nocache=" + 



* 82 /Dicembre 2007 



http://www.ioprogrammo.it 



080-085:072-080 30-10-2007 17:03 Pagina 83 



Una forni per il login in Flex ■ T SISTEMA 



new 
Date().getTime(); 



-0- 



var myXMLURL:URLRequest = 
new URLRequest(XMLJJRL); 



myLoader = new URLLoaderQ; 



Per accedere fisicamente ai dati caricati, va defi- 
nito un event-handler per l'evento Event.COM- 
PLETE, che sarà richiamato quando l'operazione di 
caricamento è terminata. Con la seguente riga: 

myLoader. addEventListener(Event. COMPLETE, 

xmlLoaded); 

indichiamo che F event-handler è rappresentato 
dal metodo xmlLoaded che effettua un casting del- 
le informazioni lette in un oggetto di tipo XML: 

myXML = XML(myLoader.data); 



FLEX E L'XML 

Con l'introduzione di ActionScript 3.0, l'approc- 
cio all'utilizzo di dati in formato xml è stato note- 
volmente facilitato. In particolare sono state in- 
trodotte un insieme di classi e funzionalità che 
prendono il nome di ECMAScript for XML, o più 
semplicemente E4X. 

Tra le classi specificate in E4X, quella su cui foca- 
lizzeremo l'attenzione e che useremo per leggere le 
informazioni presenti nel file di configurazione è XML. 
Come tutte le classi presenti nel paradigma E4X, 
XML è stata progettata per rendere l'accesso ai da- 
ti in formato xml intuitiva tramite l'usuale sintas- 
si basata sul (.). 

Se diamo un'occhiata al contenuto del file di con- 
figurazione, possiamo notare che l'informazione 
circa l'uri per l'autenticazione dei dati è posto in 
un attributo del nodo LoginUrl, mentre il path al- 
l'immagine di sfondo si trova nel nodo Back- 
groundlmage. 

Tuttavia, benché effettivamente si tratta di acce- 
dere a due elementi xml differenti, vederemo co- 
me la sintassi E4X permetta di accedervi in ma- 
niera molto simile. 
Le seguenti due righe permettono la lettura dei dati: 

m_url = myXML. LoginUrl. @url; 
m_backgroundImage = 

myXML.Backgroundlmage; 

Con la prima istruzione, accediamo al nodo Logi- 
nUrl, di cui leggiamo il contenuto dell'attributo 
"uri", mediante la sintassi (.) ed l'operatore (@) il 
quale specifica che, il nome che lo segue imme- 
diatamente, è il nome di un attributo. 
Accedere invece al contenuto del nodo Back- 



groundlmage avviene banalmente con la seconda 
istruzione. 

Si nota, quindi, come sia effettivamente molto sem- 
plice accedere agli elementi di una struttura xml, e 
questa semplicità è mantenuta anche in caso di 
scrittura. 

Per quanto riguarda le nostre informazioni di con- 
figurazione noi siamo interessati solo alla loro let- 
tura, ma se ci trovassimo nella condizione di do- 
ver persistere la modifica di una di queste, non do- 
vremmo effettuare alcun sforzo. 
Infatti se volessimo salvare nell'attributo "uri" la 
stringa " www.google.it ", ci basterebbe scrivere: 

myXML.LoginUrl.@url = "www.google.it"; 

E' possibile anche effettuare lettura o scrittura ba- 
sate su di un filtro. Supponiamo che il nostro file xml 
abbia una struttura del tipo: 

<orders> 

<order id = 'l'> 

<article>articlel</article> 
<price>3.95</price> 



</order> 



<order id = '2'> 



<article>article2</article> 



<price>1.45</price> 



</order> 



</orders> 



In lettura possiamo usare la sintassi: 



myXML.item.(@id = = 2).article; 
myXML.item.(article=="articlel").price 



mentre in scrittura, sugli stessi campi: 



myXML.item.(@id = = 2).article = "new article2"; 
myXML.item.(article=="articlel").price = 100.00; 



ARCHITETTURA 
DELLA APPLICAZIONE 

Una volta superata la pagina di login, cosa si pre- 
senterà all'utente riconosciuto ? In base al suo ac- 
count l'utente potrà essere diretto verso la pagina 
di gestione del Music Shop, se amministratore, op- 
pure verso la pagina di consultazione dell'elenco ed 
nel caso di un "cliente". 

Impropriamente ho usato il termine "pagina", più 
adatto ad una applicazione web tradizionale. In 
effetti, comunque, l'utente si troverà di fronte ad una 
interfaccia diversa da quella iniziale di login. Come 
preparare queste due nuove "pagine" ? Vedremo 
ora come realizzare le due interfacce, in due modi, 
ognuno con i suoi difetti e pregi. 




L'ELENCO DEI 
VALIDATORS 

Potete trovare un 
elenco completo dei 
validators messi a 
disposizione dal Flex 
SDK al seguente 
indirizzo: 

http://livedocs.adobe. 
com/flex/2/langref/m 
x/validators/package- 
detail.html 



Mentre per un 
approfondimento sui 
meccanismi di 
validazione: 
http://www.adobe.co 
m/devnet/flex/quickst 
art/va lidating data/ 



http://www.ioprogrammo.it 



Dicembre 2007/ 83 ^ 



080-085:072-080 30-10-2007 17:03 Pagina 84 



SISTEMA T I Una forni per il login in Flex 




■€+ 



XML SUL WEB 

Per il supporto di 

Flex all' XML fare 

riferimento alla 

documentazione 

disponibile all'uri: 

http://livedocs.adobe.co 

m/f I ex/2/d ocs/wwh e I p/w 

whimpl/common/html/ 

wwhelp.htm?context=L 

iveDocs Parts&file=000 

01910.html 



STATI VS MODULI 

Per organizzare la nostra interfaccia in modo che 
si adatti in risposta alla interazione con l'utente, 
Flex ci mette a disposizione i tags mxistates ed 
mxistate. Possiamo aggiungere degli stati alla no- 
stra applicazione in maniera molto semplice. Spo- 
standoci in modalità design, apriamo la vista Sta- 
tes dal menu Window | States. Comparirà quindi la 
finestra States, e premendo il pulsante "New Sta- 
te" potremo aggiungere un nuovo stato, per il qua- 
le dovremo definire il nome. 
La finestra contenente la maschera di login, rap- 
presenta lo stato di base della nostra applicazio- 
ne. Facendo un riferimento alla programmazione 
ad oggetti, possiamo immaginare che ciascun sta- 
to che andiamo a creare rappresenti una sorta di de- 
rivazione dall'interfaccia dello stato base. Infatti, non 
appena creiamo un nuovo stato, esso a livello di 
elementi presenti nella maschera, sarà uguale al- 
la maschera di login. 

Creiamo quindi uno stato e chiamiamolo "Admin- 
State". Esso comparirà nell'elenco degli stati presente 
nella finestra degli stati. Se ci spostiamo tra lo sta- 
to "AdminState" e quello base, cliccando rispetti- 
vamente sul loro nome nell'elenco, notiamo che 
in design non cambia nulla, tranne per il nome 
dello stato corrente visualizzato nella parte supe- 
riore della design view. Adesso spostiamoci nello sta- 
to "AdminState" e cancelliamo tutto ciò che è pre- 
sente sullo stage. Ripetiamo l'operazione di sele- 
zionare alternativamente i due stati ed adesso ve- 
diamo che qualcosa è cambiato. Aggiungiamo un 
altro stato, "UserState", eliminiamo i componenti 
ereditati, e spostiamoci in source view, per vedere 
la struttura di tag relativa agli stati. 
Questa si presenta così: 

<mx: states > 

<mx:State name="AdminState"> 

<mx:RemoveChild target="{imagel}"/> 
<mx:RemoveChild target="{controlbarl}"/> 
<mx:RemoveChild target="{pnlLogin}"/> 

</mx: State > 

<mx:State name="UserState"> 

<mx:RemoveChild target="{controlbarl}"/> 
<mx:RemoveChild target="{pnlLogin}"/> 
<mx:RemoveChild target="{imagel}"/> 

</mx: State > 
</mx: states > 



La nidificazione degli strati non ha limite, ogni sta- 
to può avere una serie di suoi sotto stati e così via. 
Tra tutti gli stati ve ne uno che è indicato come Start 
State, che rappresenta l'interfaccia che ci viene 
presentata alla partenza dell'applicazione. Se non 
definiamo nessuno degli stati creati come Start 
State, il primo stato è per default quello dello sta- 
ge iniziale o Base State. Lo stato di partenza può 



essere anche definito mediante la proprietà cur- 
rentState del tag mx: Application. 




Figura 3: La gerarchia degli stati dopo il nostro interven- 
to. 



Creati i due stati, per l'amministratore e l'utente, pas- 
siamo a caratterizzarli in qualche modo. Selezioniamo 
lo stato "AdminState" e posizioniamo su di esso, 
selezionandolo dal pannello dei Componenti, un 
Datagrid. Perlo stato "UserState", scegliamo inve- 
ce un componente DateChooser. Fatto questo scri- 
viamo nel metodo SendData il seguente codice: 

if((this.txtllserName.text== "Admin") && 

(this.txtPassword.text == "Adminl")) 

{ 

this.currentState = "AdminState"; 

} 

else 

{ 

if((this.txtllserName.text = = 
"User") && (this.txtPassword.text == "Userl")) 

{ 

this.currentState = 
"UserState"; 

} 

else 

{ 

Alert.show("Autenticazione fallita !!"); 

} 



Questo, oltre a definire i due utenti al momento ri- 
conosciuti dal sistema, permette di cambiare stato, e 
quindi interfaccia presentata all'utente, in base al ri- 
conoscimento effettuato. 

Cosa può esserci di svantaggioso nell'utilizzare gli 
stati ? Come possiamo vedere ritornando in modalità 
source view, tutti gli elementi grafici che inseriamo 
su ciascuno stato, sono inseriti all'interno del tag 
mx:State relativo. Una interfaccia complessa, con più 
stati, e magari anche con sottostati, può rendere com- 
plesso il codice mxml, se volessimo apportare delle 
modifiche direttamente in source view. Uno scenario 



+ 84 /Dicembre 2007 



http://www.ioprogrammo.it 



080-085:072-080 30-10-2007 17:03 Pagina 85 



Una forni per il login in Flex ■ T SISTEMA 



-e- 



di questo tipo non è poi molto fantasioso, si pensi al- 
la definizione delle informazioni di DataBinding. Per 
definire le quali potremmo sempre usare le proprietà 
del controllo, ma magari stiamo definendo variabli e 
metodi nel codice e quindi ci viene naturale spostarci 
nella parte relativa ai tag per completare gli aggan- 
ci. Un altro svantaggio è la effettiva non modulariz- 
zazione dell'architettura. In fondo, anche se logica- 
mente, i diversi stati sono definiti come separati, es- 
si si trovano sempre codificati nello stesso file fisico. 



I MODULI 

Una alternativa agli stati, nella implementazione del- 
la architettura di sviluppo, è rappresentata dai cosi- 
detti moduli. Questi non sono altro che dei file .swf che 
possono essere caricati, da una o più applicazioni, e 
"scaricati" quando non più necessari. Qui di seguito 
vedremo come realizzare ed utilizzare i moduli, ma 
per una trattazione più approfondita dell'argomen- 
to vi rimando al link indicato nel box laterale. Il Flex 
Builder non mette a disposizione un meccanismo 
semplice per la loro creazione come avviene nel ca- 
so di una applicazione MXML. Però, dato che un mo- 
dulo, in termini di codice mxml, è molto simile ad 
una applicazione, possiamo creare una mxiApplica- 
tion e poi convertirla in mxModule. Infatti il corpo 
di un modulo, ridotto ai minimi termini corrisponde 
al seguente codice: 

<?xml version="1.0" encoding = "utf-8"?> 
<mx:Module 

xmlns:mx=http://www. adobe.com/2006/mxml 
layout="absolute"> 

</mx:Module> 

Una volta creato il modulo, la sua compilazione 
mediante il Flex Builder, non richiede alcun inter- 
vento in quanto il modulo sarà compilato insieme 
al resto dell'applicazione. Il file .swf prodotto dal- 
la compilazione, non potrà essere fruito se non 
dall'applicazione principale, quindi richiamarlo 
in un Flash Player non sortirà effetto. 

I moduli, poi, essendo dei file eseguibili, pur con la 
limitazione appena indicata, devono necessariamente 
trovarsi nella directory principale, insieme al file 
dell'applicazione. 

Per trasformare la nostra applicazione, da basata su- 
gli Stati a basata sui Moduli, aggiungiamo un ulte- 
riore stato chiamato "ModulesStageState" elimi- 
niamo i componenti ereditati e inseriamo al cen- 
tro dello stage dello stato un componente mxiVBox, 
presente tra i componenti di layout. 

II nuovo stato servirà da contenitore per tutti gli 
eventuali moduli utilizzati dal Music Shop. Fatto 
questo, il metodo SendData subirà alcune piccole 



modifiche in modo che, al riconoscimento dell'u- 
tente, sia caricato il modulo corretto. Ad esempio, 
in caso di utente amministratore: 

theModule = 
ModuleManager.getModule("AdminModule.swf"); 
theModule. addEventl_istener(ModuleEvent. READY, 

adminModuleReady); 
theModule. load(); 

Queste tre righe, mediante la classe ModuleMa- 
nager effettuano il caricamento del modulo "Ad- 
minModule.swf ". Inoltre essendoci registrati all'e- 
vento ModuleEvent. READY, quando il modulo è 
stato caricato, possiamo rendere corrente lo stato 
"ModulesStageState" e aggiungere alla display li- 
st del componente layout VBox l'istanza del mo- 
dulo, in modo da visualizzarla. 

this.currentState = "ModulesStageState"; 
this.vbAdmin.addChild(theModule.factory.create() as 

AdminModule); 



COMUNICAZIONI 
APPLICAZIONE - MODULI 

La comunicazione tra l'applicazione principale ed 
i suoi moduli è bidirezionale. Infatti dalla applica- 
zione è possibile utilizzare proprietà e metodi di 
un modulo utilizzando la proprietà facto ry della 
classe ModuleManager. Per accedere ad un meto- 
do del modulo AdminModule, sarà sufficiente ac- 
cedere all'istanza del modulo e quindi richiama- 
re il metodo: 

var m:Object = 
theModule. factory.create() as AdminModule; 
m.MetodoPresentel\lelModulo(); 

Viceversa, la comunicazione tra modulo ed appli- 
cazione avviene quasi banalmente attraverso la 
proprietà, del modulo, parentApplication: 

parentApplication.ProprietàDellaApplicazione; 
parentApplication. MetodoDellaApplicazioneO; 



CONCLUSIONI 

Due parole in conclusione. Vi lascio ad una lenta di- 
gestione dei concetti esposti finora in attesa della 
prossima puntata in cui si comincerà a lavorare 
con dati "reali" in quanto, finalmente, stabiliremo 
una comunicazione con la parte server dell'appli- 
cazione Music Shop. 

Giuseppe Dattilo 




AGGIORNARE 
FLEX 

Per una trattazione 
esaustiva dell'uso dei 
Moduli in Flex, 
scaricate 

l'aggiornamento del 
capitolo 31 del 
manuale del Flex 
SDK dall'indirizzo 
http://blogs.adobe.com/ 
flexdoc/pdfs/modular.p 
df 



http://www.ioprogrammo.it 



Dicembre 2007/ 85 ^ 



086-093:032-035 2-11-2007 12:01 Pagina 86 



Sistema T ■ Tecniche di programmazione in C++ 



DIECI COSE 

DA NON FARE IN C++ 

CHI INIZIA COL C++ È SEMPRE PORTATO A FARE GLI STESSI ERRORI. QUESTI A VOLTE PRODUCONO 
PROGRAMMI MALFUNZIONANTI, BUG CRITICI, O SEMPLICEMENTE LO SCHERNO DA PARTE DEI 
PIÙ ESPERTI. ECCO COME EVITARLI. 



-0- 





Conoscenza di base 
del C++ 



Un compilatore 
C++ standard 



Tempo di realizzazione 



c 



envenuti al nostro appuntamento mensile 
col C++. In questo anno abbiamo analizzato 
librerie, pratiche e stili da utilizzare per 
migliorare la programmazione in questo linguag- 
gio potente e complesso. Molto complesso. 
Soprattutto perché è necessario imparare tanto 
cosa fare in C++ quanto (e soprattutto) cosa non 
fare. Puntualmente, svolgendo la mia attività di 
docente e frequentando qualche gruppo di discus- 
sione, mi è capitato di sentire programmatori, 
soprattutto novizi, ripetere per l'ennesima volta gli 
stessi errori, o le stesse leggende metropolitane. 
In questa puntata ne ho riassunti dieci fra quelli 
che considero più gravi o più diffusi. Nella maggior 
parte dei casi si tratta di errori di inesperienza, e il 
discorso si rivolgerà quindi ai neofiti. Alcuni risvol- 
ti, comunque, potrebbero sorprendere più di un 
programmatore di media esperienza. Se seguite 
puntualmente questa rubrica, vedrete rispuntare 
fuori argomenti già trattati in quest'anno: conside- 
rate questa puntata come un buon riassunto. Ma 
potete anche vederla come un buon antipasto: 
alcune delle indicazioni presenti in questo decalo- 
go, infatti, faranno da spunto per le serie dei pros- 
simi mesi. Ed ora, ecco a voi la top ten degli orrori 
in C++: 



1) "COMPILA, 
QUINDI E GIUSTO!" 

Questo non è un errore, di per sé. Ciò nonostante si 
conquista senza alcun dubbio la prima posizione 
in quanto capostipite di una numerosa famiglia di 
errori. Si tratta dell'atteggiamento tipico del neofi- 
ta, che, un po' per inesperienza e un po' per pigri- 
zia pensa che il fatto che un compilatore accetti 
una scrittura implichi necessariamente che questa 
sia corretta. Non è cosi. L'unica fonte attendibile 
che stabilisce cosa sia da considerarsi corretto nel 
C++ è lo standard. Non sono attendibili tutte le 
fonti che non fanno riferimento allo standard e 
ancor meno il comportamento dei compilatori. I 
compilatori, infatti, applicano spesso qualche 



deviazione o estensione rispetto al C++ standard, e 
devono necessariamente adottare qualche arbitrio 
nell'interpretazione dei famosi comportamenti 
dipendenti dall'implementazione, non specifi- 
cati, o indefiniti. Facciamo un test pratico, dedica- 
to soprattutto ai lettori esperti: 



#include <iostream> 




int main() { 


signed char n 


= 127; 


std::cout << 


int(++n); 


} 



Quale sarà l'output dell'applicazione? Provate 
a rispondere da voi, prima di continuare la let- 
tura. 

Fatto? L'unica risposta corretta è: "boh?". 
Questo, infatti, è un tipico caso di comporta- 
mento indefinito. Non si sa cosa succederà in 
esecuzione, perché lo standard non stabilisce: 

• Il valore massimo di char. Il fatto che un 
char debba occupare al minimo 1 byte e che 
quasi sempre questa misura sia anche quel- 
la effettiva, non significa che un char non 
possa essere rappresentato con 2, 3 o 10 
byte. Potete controllare il valore massimo di 
un signed char richiamando la funzione 
std::numeric_limits<signed char>::max(). Se 
questo valore è maggiore di 127, verrà stam- 
pato semplicemente 128. Altrimenti avverrà 
un overflow. 

• Che cosa succede in caso di overflow di un 
valore signed: dato che la stragrande mag- 
gioranza delle architetture usa il comple- 
mento a due, è probabile che il numero 
riparta dal valore minimo (-128). Ma anche 
no. Potrebbe rimanere 127. O l'applicazione 
potrebbe andare in crash. 

Potete inventarvi il comportamento che 
volete: tanto lo standard non dice nulla a 
riguardo. 



* 86 /Dicembre 2007 



http://www.ioprogrammo.it 



086-093:032-035 30-10-2007 17:04 Pagina 87 



Tecniche di programmazione in C++ ■ T Sistema 



-e- 



tutti, specialmente negli esempi infidi in un 
linguaggio insidioso come C++. Il punto è un 
altro: se lo provate sul vostro compilatore di 
fiducia e questo stampa "255", o "65535" o arre- 
sta l'applicazione, o qualsiasi altra cosa, non 
significa che questo sia il comportamento 
"giusto". (In questo caso, infatti, non c'è un 
comportamento "giusto"). 
Il ricorso allo standard non serve per farvi 
diventare l'ennesimo language lawyer capace 
di discutere per ore con un collega recitando il 
paragrafo 57, comma Q, sezione 0xA4 del Libro 
dei Libri; ha un valore pratico. 
Se scrivete software portabile, l'attenzione a 
non cadere nel comportamento indefinito o a 
non dare per scontato un comportamento 
dipendente dall'implementazione vi rispar- 
mierà ore di debug, quando non riuscirete a 
capire perché quel codice "così ovvio" funzioni 
perfettamente sulla piattaforma X, ma sballi 
inspiegabilmente su quella Y. 



2) VOID MAINO 

Quest'errore è una specie di marchio d'infa- 
mia; è considerato universalmente: "il biglietto 
da visita dell'ignorante in C++". 
Il fatto che il vostro compilatore accetti scrittu- 
re come void main(void), o void mainO, o 
mainQ senza obiettare il minimo warning, non 
significa che queste siano corrette. (Ma proba- 
bilmente significa che dovreste pensare seria- 
mente a cambiare compilatore). 
Neanche il fatto che il vostro manuale abbia 
ripetuto dalla prima all'ultima pagina void 
main(void), significa che questa scrittura sia 
corretta. (Ma vi spiega perché gli esperti vi 
scongiurano di buttare via i libri di Schildt, per 
esempio). 

Immagino che la conclusione di questo pream- 
bolo sia chiara, alla luce del paragrafo prece- 
dente: l'unica autorità col potere di decidere 
cosa sia universalmente giusto, è lo standard. E 
void mainQ non lo è. 

Secondo lo standard ISO C++ (vedi 3.6.1 [2]), 
infatti, le uniche due scritture universalmente 
ammesse sono: 

int main() 



int main(int argc, char* argv[]) 



secuzione i programmi restituiscono sempre 
un intero al chiamante. A tal proposito, questo: 



#include <iostream> 




int 


main() { 












std: 


:cout << 


"Io 


sono 


standard!\n"; 


} 



è un programma corretto secondo lo standard, 
anche se manca l'istruzione return. In questo 
caso, infatti, viene restituito implicitamente in 
valore (che nei sistemi POSIX significa: "tutto 
è andato bene"). 
Già che ci siamo, la scrittura: 

main() 

Non è corretta secondo il C++ standard (men- 
tre lo è secondo il C '89), perché il C++ non 
assume implicitamente int per le funzioni che 
non presentano un tipo di ritorno. 
Voglio ribadire un concetto importante: i com- 
pilatori hanno tutto il diritto di permettere 
altre scritture di main. Possono in linea teorica 
esistere compilatori che permettono long 
mainQ, o char* mainO, e sicuramente anche 
void mainO, dato che possono esserci casi in 
cui in cui il sistema... semplicemente non esi- 
ste. 

Il problema è che tutte queste sono eccezioni, 
estensioni del linguaggio: pochi compilatori 
accetteranno scritture come void mainO, ma 
tutti sono obbligati ad accettare int mainQ. È 
questa la forza e la sicurezza di scrivere in C++ 
standard (oltre a non farvi prendere in giro da 
gente su Internet che vive per divertirsi alle 
spalle dell'ennesimo novellino che osi scrivere 
void main (void)). 



3) «INCLUDE 
<IOSTREAM.H> 

Quest'errore appartiene al regno del " codice 
che era valido una volta, ma da allora sono pas- 
sati almeno dieci anni". Ecco un esempio: 



//nota: 


questo codice è 


(come minimo) deprecato 


#include <iostream.h> 




int main() { 




cout << "Ciao, 


mondo! 


' << 


endl; 


} 




La costante è che in entrambi i casi il tipo resti- 
tuito dev'essere int. E in effetti questo ha un 
senso, perché nei sistemi POSIX alla fine dell'e- 



Qualunque libro o tutorial vi presenti oggi un 
"hello world" del genere è molto vecchio, o 
molto scadente (in ogni caso, passate ad altro). 



http://www.ioprogrammo.it 



Dicembre 2007/ 87 ^ 



086-093:032-035 30-10-2007 17:04 Pagina 88 



Sistema T ■ Tecniche di programmazione in C++ 




-e- 



I file della libreria standard che terminavano 
con ".h" sono stati deprecati - ed è successo 
più di dieci anni fa! 

Gli header "moderni" non hanno alcun'esten- 
sione (come <iostream>), e presentano molti 
vantaggi rispetto ai vecchi: utilizzano il name- 
space std, sono fortemente orientati ai tem- 
plate e si integrano molto meglio col resto 
della libreria standard. L'equivalente moderno 
del programma qui sopra è: 



#include <iostream> 




int main() { 


std::cout << "Ciao, mondo!' 


<< 

std: 


:endl; 


} 



Nel nuovo codice è obbligatorio qualificare i 
nomi della libreria standard, usando il prefisso 
std::. Se non volete allungare eccessivamente 
il codice, potete usare la direttiva using name- 
space: 

#include <iostream> 

int main() { 

using namespace std; 

cout << "Ciao, mondo!" << endl; 



Molti programmatori tendono però ad abusa- 
re di questa direttiva, annullando così tutti i 
vantaggi dei namespace (cioè di evitare colli- 
sioni fra i nomi che create voi e quelli che usa 
la libreria standard). Pertanto, cercate di usar- 
la solo se i nomi standard vengono usati tanto 
estensivamente che gli std:: complicano 
davvero la lettura. E cercate sempre di posizio- 
narla quanto più internamente possibile. Una 
cattiva pratica molto diffusa, ad esempio, è 
definire un using namespace globale: 



#include <iostream> 




using namespace 


std; 


//perché 


all'esterno? 




int main() { 


cout << 


"Ciao, mondo 


" << 


endl; 


} 



Purtroppo al mondo c'è un numero sorpren- 
dente di programmatori che non si interessa- 
no né dello standard, né tantomeno dello stile 
(sono quelli del tipo: "compila quindi è giu- 
sto!"). Così, ad un certo punto, gli scrittori di 
compilatori hanno capito che Tunica strada 
per far smettere di usare <iostream.h>, consi- 



steva nel togliere i file ".h" dalle loro imple- 
mentazioni della libreria standard. 
Questa è probabilmente la ragione definitiva 
che dovrebbe spingervi ad evitare l'inclusione 
di file di libreria ".h": sulla maggior parte dei 
compilatori più importanti, semplicemente 
non esistono. 



4) #DEFIIME PI 3.1415 

Questo ricade in quella (vasta) categoria di 
errori commessi da tutti i neofiti che pensano 
che il C e il C++ siano "più o meno la stessa 
cosa". È vero che il C++ è (quasi) un soprainsie- 
me del C, ma le funzionalità aggiunte sono tal- 
mente tante da cambiare radicalmente le pra- 
tiche di programmazione. Non di rado capita 
che ciò che è caldamente raccomandato in C, 
sia fortemente sconsigliato in C++ (e vicever- 
sa). 

Usare #define per definire delle costanti, ad 
esempio, è tipico in C, perché la parola chiave 
const non vincola sufficientemente il pro- 
grammatore. In C++, invece, const è una cosa 
seria: un vincolo che è impossibile aggirare, se 
non per mezzo di orrendi const_cast. 
Usare #define non permette al compilatore di 
inserire la costante all'interno della tabella dei 
simboli, perché all'unità di traduzione tale 
costante non arriva nemmeno: viene intercet- 
tata e sostituita dal preprocessore. In questo 
modo ottimizzazioni, controlli, messaggi di 
errore significativi, diventano tutti sogni 
impossibili. 

Un programmatore C++ usa const ogni volta 
che può, in tutte le sue accezioni possibili: 

//definizione di costante (e non semplice macro) 
const Pi = 3.1415; //non #define PI 3.14592 

//passaggio per riferimento costante 
//(usate la copia soltanto per tipi semplici o 

primitivi) 

void Funzione(const Oggetto^); //non void 

Funzione(Oggetto) 

//funzione membro costante 

void Oggetto: :Funzione() const {} 

Un errore ancora peggiore è l'uso del prepro- 
cessore per definire funzioni, come questa: 

#define ABS(n) n > ? n : -n 

A parte il tipico errore di omettere le parente- 
si attorno all'argomento (n), questo tipo di 
macro è un generatore perpetuo di sorprese e 



+ 88 /Dicembre 2007 



http://www.ioprogrammo.it 



086-093:032-035 30-10-2007 17:04 Pagina 89 



Tecniche di programmazione in C++ ■ T Sistema 



bug critici. Se non ci credete, provate a scri- 
vere: 



-0- 



#define 


ABS( 


n) (n) > 


0?(n) 




-(n) 




int mair 


{ 












int n 


= 0; 










std: 


cout << 


ABS(n- 


-) 




} 



Qual è l'output del programma? Sorprese 
come questa vi spiegano perché in generale gli 
esperti di C++ vedano di pessimo occhio l'uso 
del preprocessore (se non per il controllo con- 
dizionale della compilazione con #ifdef). In 
casi come questo C++ ha, peraltro, un'alterna- 
tiva migliore sotto ogni aspetto: le funzioni 
template inline. 



template<typename 


T> 


inline T Abs(T n) { 


return n > ? n 


-n; 


} 




int main() { 


std::cout << Abs(-lO); 




} 



Poiché la funzione è template, è valida per 
ogni tipo (anche non primitivo, volendo), pro- 
prio come la macro. Poiché è inline, verrà 
espansa nel codice, proprio come la macro. 
Ma a differenza della macro, sarà una fun- 
zione, sotto stretto controllo del compilatore. 



5) CHAR* STRINGA 

Quest'errore ricade nella stessa categoria del 
precedente. Mentre in C gli array di char sono 
comunissimi, nel mondo C++ le stringhe pri- 
mitive sono viste come una delle principali 
fonti di bug, e vengono usate solo in casi in cui 
le prestazioni non permettono altro (e sono 
casi rari) . 

Assieme alle creme antibrufoli, gli array di 
char sono il paradiso dei cracker: dei buffer a 
lunghezza fissa terminati dal carattere nullo. 
Sembrano inventati apposta per permettere il 
prossimo exploit da stack-based overflow! 
Il C++ offre al programmatore il tipo 
std::string (o basic _string<T>, se preferite un 
approccio più generico), che evita ogni genere 
di fastidio permettendo operazioni di copia, 
assegnamento, ricerca, sostituzione, iterazio- 
ne, e mille altre meraviglie, sotto forma di 
semplici funzioni membro. Oltre a queste, 



potete mettere nel computo anche tutti gli 
algoritmi STL di <algorithm> e l'integrazione 
con le altre componenti della libreria standard 
(come stringstream, ad esempio). 
Questo errore è soltanto un caso particolare. 
In generale, evitate di usare (e soprattutto pas- 
sare in giro) degli array: preferite loro dei vec- 
tor (o se proprio volete la lunghezza fissa, pro- 
vate con boost::array). Non usate <cstdio>, 
usate gli stream. Non usate il C, usate il C++ (e 
questo comprende la libreria standard) . 



6) VOID* FUNZIONE 
(INT NARGS, ...) 

Il C++ è un linguaggio tipizzato fortemente e 
staticamente, e l'attenzione per il type- 
checking è molto maggiore rispetto a quanto 
avviene in C. I controlli effettuati dai compila- 
tori C++ sono impietosi, ed evitano che a run- 
time succedano "cose strane", come ad esem- 
pio che un intero venga interpretato come se 
fosse una stringa, mandando in crash il pro- 
gramma (nel migliore dei casi). 
Anche in C esistono controlli simili ma, come 
abbiamo visto nel paragrafo sul qualificatore 
const, sono molto meno rigidi. 
In C è comune, ad esempio, usare funzioni che 
operano per ellissi, ovverosia con parametri di 
numero e tipo variabile. La funzione printfne 
è l'esempio principe: 



#include <cstdio> //e 


non 


<stdio.h>! 


int 


main() { 






std 


:printf("%s %s!", 


ciao, 


mondo); 


} 



Quale sarà il risultato dell'esecuzione? 
Dipende dal valore e soprattutto dal tipo delle 
variabili ciao e mondo. Nel caso seguente, l'e- 
secuzione andrà a buon fine: 



const char* 


ciao = 


"Ciao"; 


const char* 


mondo 


= "mondo"; 


Ma in quest'altro, 


proprio no. 


int ciao = 1; 


char mondo 


= 2; 





Possiamo solo immaginare cosa succederà in 
un caso simile. Probabilmente un crash del- 
l'applicazione, o un mare di scritte strane, o 
entrambe le cose. Stesso discorso per quest'i- 
struzione: 

std::printf("%s %s!", "Ciao, Mondo!"); 




http://www.ioprogrammo.it 



Dicembre 2007/ 89 ^ 



086-093:032-035 30-10-2007 17:04 Pagina 90 



Sistema T ■ Tecniche di programmazione in C++ 




-e- 



In questo caso il tipo dei parametri è giusto ma 
è il loro numero ad essere sbagliato (ne manca 
uno!). Altro crash a tempo di esecuzione, 
impossibile da prevedere per un compilatore. 
È per questo che il C++ ha un sistema di 
stream, perfettamente sicuro rispetto ai tipi. 
Se proprio non vi piace o avete bisogno di una 
stringa di formattazione, potete usare stru- 
menti C++ sicuri, che traggano vantaggio dal- 
l'overloading degli operatori, come il 
boost::format che abbiamo visto su questa 
stessa rubrica nell'Aprile 2007. 
Ma l'ellissi non è che una delle operazioni volte 
ad aggirare pericolosamente i controlli del 
compilatore. Anche alcuni esempi di upcasting 
su tipi non-polimorfi sottraggono irrimediabil- 
mente informazioni al compilatore, e va anco- 
ra peggio con alcuni esempi di type punning 
che vengono visti male persino in C, come 
questi: 



istruzioni intermedie 



union 


Variant { 








int intero; 


char* stringa; 


}; 




void* 


tipoGenerico = re 


nterpret_ 


_cast<void* 


>(x); 



Entrambi i casi rendono impotente il compila- 
tore di fronte a vostri eventuali errori. Quando 
usate la union ci si può solo fidare che stiate 
leggendo dal campo corretto, e quando ripri- 
stinate il casting da void*, c'è solo da pregare 
che azzecchiate il tipo originale di x, qualun- 
que esso fosse. 

Morale della favola: in C++ il compilatore è il 
vostro migliore amico. Prenderlo in giro è una 
gran brutta azione, e spesso si paga. 



delete x 

Poi assicuratevi che fra il new e il delete non ci 
siano punti di uscita, anche impliciti. Se una 
delle istruzioni intermedie è in grado di lancia- 
re un'eccezione, ad esempio, x sarà a rischio di 
memory leak. E, ancora peggio, se x detiene 
delle risorse (un file, un hook, una qualunque 
risorsa di sistema), queste non verranno mai 
rilasciate, perché il distruttore non sarà mai 
eseguito. 

In C++ si usa la tecnica RAII per la gestione di 
questi problemi. Abbiamo dedicato ben quat- 
tro puntate di questa rubrica ad analizzarle 
(dal Dicembre 2006 al Marzo 2007). 
Potete creare una classe RAII, potete usare gli 
smart pointer, potete usare uno ScopeGuard 
come quello fornito da Loki (e che vedremo in 
uno dei prossimi appuntamenti), potete addi- 
rittura utilizzare un garbage collector, ma non 
usate mai la coppia new/delete da sola, senza 
l'analisi delle istruzioni intermedie e dei punti 
di uscita. 

Per quanto riguarda le funzioni, se proprio 
dovete crearne una che restituisca un puntato- 
re a memoria dinamica (tipicamente per pre- 
servare il polimorfismo), assicuratevi quanto- 
meno di incapsularla in un auto_ptr. 

struct Mostro {}; 

struct Zombie : Mostro {}; 

struct Mostriciattolo : Mostro {}; 

std: :auto_ptr<Mostro> CreaMostro(const 

std::string& tipo) 



if (tipo == "Zombie") 



7) RETURN 
NEW INT[200] 



La gestione della memoria è uno dei punti cri- 
tici del C++. Vi è concesso controllare fino 
all'ultimo bit, gestire allocazioni e deallocazio- 
ni direttamente e in maniera più furba ed effi- 
ciente di come potrebbe fare un garbage col- 
lector. Ma vi è anche concesso di fare grandi 
danni, e di complicare la vostra applicazione al 
punto da non riuscire più a capire se e quando 
una risorsa sia stata allocata, o distrutta. 
Per questo la gestione diretta della memoria (e 
delle risorse!) è quasi sempre un male. Ogni 
volta che scrivete un'istruzione new, vi consi- 
glio di sollevare un sopracciglio. 
Innanzitutto assicuratevi che esista una corri- 
spettiva istruzione delete. 



return std: :auto_ptr<Mostro>(new Zombie); 



else 



return std: :auto_ptr<Mostro>(new 

Mostriciattolo); 



} 



In questo modo se il chiamante ignorerà il 
risultato di CreaMostro, questo sarà distrutto 
automaticamente. E se, invece, il chiamante 
vorrà usare il mostro, sarà obbligato a gestirlo a 
sua volta attraverso uno smart pointer. 
Per quanto riguarda le classi, non restituite in 
nessun caso riferimenti o puntatori diretti alle 
risorse che queste detengono: 



class Bitmap { 


char* rawData_ 


; //Dati dei Pixel 


public: 



* 90 /Dicembre 2007 



http://www.ioprogrammo.it 



086-093:032-035 30-10-2007 17:04 Pagina 91 



Tecniche di programmazione in C++ ■ T Sistema 



char* GetRawDataQ { //NO! 



-0- 



return rawData_ 



}; 



//... altre funzioni membro 



}; 



Nel caso giocattolo presentato qui sopra, la 
classe Bitmap detiene un buffer allocato dina- 
micamente (rawDataJ, contenente il valore di 
ogni singolo pixel, ed espone una serie di fun- 
zioni membro (come SetPixel(x, y, colore), 
eccetera...), per modificarlo. E, ovviamente, 
dealloca il buffer nel suo distruttore. 
Tutto questo assicura che, se la classe Bitmap è 
ben fatta, non potranno esserci dei leak di 
memoria o di risorse. Se, però, create una fun- 
zione membro come GetRawData, che espone 
direttamente il buffer, avete vanificato tutto in 
un colpo solo. L'utente potrà giocarci a suo pia- 
cimento, deallocarlo, corromperlo, il tutto in 
barba alla classe Bitmap che non avrà più 
alcun controllo su risorse che dovrebbero esse- 
re soltanto sue. 



8) CLASS O STRUCT? 

Il finale del paragrafo precedente è in realtà 
solo un caso particolare di un errore più gene- 
rico e molto frequente nei principianti: 
confondere classi e strutture. 
Cominciamo a sfatare un luogo comune molto 
diffuso, e cioè che la parola chiave struct sia 
"meno potente" di class. Le strutture permetto- 
no di definire costruttori, distruttori, funzioni 
membro (anche virtuali), liste di tipi da cui ere- 
ditare, operatori da sovraccaricare, eccetera... 
esattamente come le classi. 
Allora qual è la differenza? Da un punto di vista 
formale, l'unica differenza è che nell'elenco 
delle superclassi e dei membri di una struttura 
viene sottintesa la parola chiave public, anzi- 
ché private. 

class Zombie : Mostro //Ereditarietà privata 

_i 

ZombieQ; //Costruttore privato! 



struct Zombie : Mostro //Ereditarietà pubblica 

{ ~ 

Zombie(); //Costruttore pubblico 



Questa piccola differenza sintattica, riflette, 
però un'enorme differenza a livello concettua- 
le. Le classi devono nascondere, mentre le 



struct normalmente si preoccupano solo di 
mostrare. 

Una struct consiste solitamente in un insieme 
di dati membro pubblici, con l'aggiunta (tal- 
volta) di qualche operatore o funzione mem- 
bro pubblica. Un utente può tranquillamente 
modificarne ogni campo, senza paura di com- 
prometterne l'integrità: 



struct Punto { 


int x; 


int y; 


}; 



Le classi, invece, mantengono al loro interno 
qualche risorsa segreta o impossibile da modi- 
ficare direttamente. Tutte le funzioni membro 
servono ad accedervi in modo controllato. 
Ecco un esempio: 

class Frazione { 

int numeratore_; 
int denominatore- 



void SemplificaQ; 



public: 



Frazione(int, int); 



int NumeratoreQ ; 



int DenominatoreQ; 



}; 



La classe Frazione ha un numeratore e deno- 
minatore privati. L'accesso viene fornito (in 
sola lettura, in questo caso) soltanto attraverso 
delle funzioni membro pubbliche. Notate che 
la classe ha anche una funzione membro per 
semplificare la frazione, ma questa non è visi- 
bile all'esterno, per il semplice fatto che non 
deve interessare all'utente. È la classe stessa a 
preoccuparsi che Semplifica venga richiamata 
automaticamente ad ogni modifica. 
In questo modo, si garantisce che non potrà 
esistere in nessun modo e in nessun momento, 
una Frazione non semplificata. Questa condi- 
zione garantita prende il nome di invariante. 
Frazione, quindi, dev'essere definita come 
class perché deve preservare l'invariante di 
essere sempre in uno stato in cui il numeratore 
e il denominatore non hanno fattori in comu- 
ne. 

Ma quando non c'è alcun'invariante da mante- 
nere, è inutile usare una classe. E invece, capi- 
ta molto spesso di vedere qualcosa di simile: 



class Punto { 


int x_; 


int y_; 


public: 




int GetXQ {return x_ 


;} 




http://www.ioprogrammo.it 



Dicembre 2007/ 91 ^ 



086-093:032-035 30-10-2007 17:04 Pagina 92 



Sistema T ■ Tecniche di programmazione in C++ 




int GetY() {return y_;} 


void SetX(int x) {x_ = x;} 


void SetY(int y) {y_ = y;} 


}; 



La classe Punto non preserva alcun invariante: 
è soltanto una serie di dati nascosti e di funzio- 
ni membro pubbliche che si limitano a resti- 
tuirli (getter) o ad assegnarli direttamente (set- 
ter). Si tratta, in sostanza, della stessa struct 
Punto che abbiamo mostrato poco fa. 
Chiamare classe un'accozzaglia di getter e set- 
ter non rende il design più OOP: è soltanto 
un'inutile complicazione. In casi come questo, 
è meglio definire Punto come una struct: si 
risparmiano linee di codice, si offre una mag- 
giore comodità all'utente, e soprattutto non lo 
si induce a credere che la classe Punto sia più 
intelligente di quanto è in realtà. 
I casi in cui è legittimo che un tipo non preser- 
vi uno straccio di invariante sono molto rari. Se 



il vostro codice espone diversi tipi sotto forma 
di struct (o, ancor peggio, di strutture masche- 
rate da classi), cominciate a chiedervi cosa non 
va nell'architettura della vostra applicazione. 



9) I++ 



Fra tutti gli errori riportati in quest'articolo, 
questo è senz'altro il meno grave, ma si guada- 
gna il posto in graduatoria per la sua eccezio- 
nale diffusione. Non è raro trovarlo anche in 
codice di qualità e persino su insospettabili 
libri di testo. 

In C++ esistono due operatori di incremento, 
uno postfisso (i++) e uno prefisso (++i). Visti 
come istruzioni, sono identici: entrambi signi- 
ficano "i = i + i". Visti come espressioni, però, 
differiscono radicalmente: i++ vale i, mentre 
++i vale i+1. 
Se il vostro grado di competenza va da "princi- 



PER APPROFONDIRE SULLA CARTA 



"0- 



Se il leggero antipasto che vi ho 
presentato con questo decalogo vi è 
piaciuto, o se vi aspettavate un menù 
più consistente, forse è il caso che diate 
un'occhiata alla vasta letteratura in 
materia. Vista la complessità del C++ e 
la serie di trappole in cui possono 
cadere i programmatori, in effetti, non 
c'è da stupirsi se più di un libro è stato 
scritto appositamente per chiarire cosa 
non fare in C++. 

C++ Gotchas, di Stephen C. Dewhurst, è 
probabilmente il più noto e completo. 
Si tratta 99 consigli su pratiche da non 
seguire. In ogni tema si discute del 
perché un certo idioma nasconda una 
trappola, e le varie soluzioni alternative 
che dovrebbero invece essere prese in 
considerazione. Caldamente consigliato. 

How Not To Program In C++, di Steve 
Oualline, è un libro molto più leggero 
del precedente. Scritto in uno stile 
molto ironico e piacevole, propone 111 
programmi "non funzionanti", 
intervallati da storielle, metafore e 
barzellette IT. Non offre una gran 
profondità, ma può essere una lettura 
simpatica, e un ottima fonte per quei 
docenti che si divertono a far ragionare 
i propri allievi. 

Imperfect C++, di Matthew Wilson, è un 
libro molto particolare, dal momento 
che discute più che altro del perché il 
C++ non possa considerarsi un 
linguaggio perfetto. Con questa scusa. 



in realtà si danno molti buoni consigli, 
in uno stile molto chiaro e colloquiale. 
A dir la verità qualche consiglio è 
discutibile, e lo stile, molto spesso, 
suona anche un po' arrogante. Ma è 
molto facile sembrare odiosi scrivendo 
libri del genere (come probabilmente 
dimostra questo stesso articolo). 

Tutti questi testi possono essere presi 
come accessori, e ognuno offre qualcosa 
di diverso. Le guide più importanti, 
tuttavia, sono i cosiddetti "secondi 
libri", quelli che devono essere studiati 
dopo il manuale introduttivo e devono 
necessariamente figurare sugli scaffali 
di qualunque programmatore C++. 

Effective C++, di Scott Meyers: 55 temi 
su pratiche da seguire e da evitare. È 
universalmente noto come il "primo fra 
i secondi libri". Se avete appena finito 
di leggere il vostro primo manuale, ci 
metterete molto tempo a digerirlo, e vi 
consiglio di tenerlo per qualche mese 
sulla scrivania mentre programmate. 

More Effective C++, altri 35 temi. Si 
tratta di un libro meno fondamentale 
del precedente, tuttavia è un'ottima 
appendice. Alcune sezioni 
sull'implementazione di smart pointer e 
dei sistemi di copy on write sono 
decisamente chiare e interessanti. 

Effective STL, è l'equivalente di 
Effective C++ per la libreria standard. 
Dal momento che i manuali solitamente 



danno qualche consiglio pratico sul 
linguaggio, ma trattano poco l'STL, è 
forse il più fondamentale dei tre 
Effective qui presentati. Se il C++ è 
insidioso, la sua libreria standard è 
ancora peggio. Indispensabile. 

C++ Coding Standards, di Herb Sutter e 
Andrei Alexandrescu. Cosa si intende 
esattamente per "stile"? Le infinite 
diatribe su come gestire le indentazioni 
e il casing delle variabili? Oppure 
queste guerre di religione mascherano 
soltanto i veri problemi? Questo testo è 
un'ottima risposta a tali domande: 
presenta 101 linee guida per lo stile su 
cui è difficile non essere d'accordo. 
Molto semplice da seguire anche per il 
neofita, questo è sicuramente un libro 
da leggere parallelamente al vostro 
primo Effective. 

Exceptionai C++, More Exceptionai C++ 
e Exceptionai C++ Style, di Herb Sutter. 
Se avete letto tutti i libri precedenti, 
siete pronti per affrontare questi tre. Si 
tratta di temi dalla forma di quiz: si 
illustra un problema, si chiede come lo 
risolvereste voi, e poi si analizzano le 
varie soluzioni possibili dando un voto 
a ciascuna. Sutter è 

contemporaneamente uno dei migliori 
esperti di C++ e uno dei migliori 
divulgatori, e fra loro è forse l'unico in 
grado di spiegare con estrema 
competenza e chiarezza come certe 
funzionalità del C++ possono essere 
implementate dai vari compilatori. 



* 92 /Dicembre 2007 



http://www.ioprogrammo.it 



086-093:032-035 30-10-2007 17:04 Pagina 93 



Tecniche di programmazione in C++ ■ T Sistema 



-e- 



piante" a "mediamente esperto", probabilmen- 
te a questo punto starete pensando: "E allora? 
Dimmi qualcosa che non so." (Se invece siete 
davvero esperti, avrete già capito dove voglio 
andare a parare. Potete evitare di leggere il 
resto del paragrafo). 

Il problema reale è che molti programmatori 
hanno un ingiustificato e morboso attacca- 
mento all'operatore postfisso. Prendiamo, ad 
esempio, il tipico programma per stampare i 
numeri da a 99. Su molti manuali, troverete 
qualcosa del genere: 



#include <iostream> 




int main() { 


//nota: questo ciclo 


è perfettibile 


for (int i = 0; i<100; 


i ++) { 


std::cout << i << std::endl; 


} 


} 



Ma siete sicuri che "i++" sia proprio l'operato- 
re più indicato? In realtà in questo caso l'ope- 
razione di incremento non viene usata come 
espressione, ma semplicemente come istruzio- 
ne. Quindi l'operatore più corretto è quello 
prefìsso: 



#include <iostream> 




int main() { 


for (int i=0; 


i<100; 


+ + i) { //OK! 




std::cout 


<< i << std: :endl; 


} 


} 



Non si tratta di una semplice questione stilisti- 
ca: c'è un vantaggio effettivo che si capisce solo 
se si conosce come funziona l'operatore post- 
fisso. Prima che la variabile venga incrementa- 
ta, viene creata una sua copia, che viene quin- 
di usata come valore dell'espressione. 
Pertanto, se scrivete "i++" come incremento 
del ciclo, fate sprecare al programma 100 ope- 
razioni di copia per un valore che non interes- 
sa a nessuno. A volte i compilatori riescono a 
capire l'errore e lo correggono, ma spesso non 
hanno i mezzi (o non sono abbastanza furbi) 
per farlo. In ogni caso, perché rischiare, quan- 
do potete scrivere semplicemente e molto più 
correttamente ++i? 

La regola è semplice: se dovete usare una varia- 
bile "i" come espressione e contemporanea- 
mente incrementarla, scrivete i++. Altrimenti 
(cioè nella maggior parte dei casi, compresi i 
cicli) usate ++i. 



IO) "IO QUELLA ROBA 

moni la uso" 

Quello che segue è uno stralcio della "Mozilla 
Compatibility Guide", che potete trovare all'in- 
dirizzo http://www.mozilla.org/hacking/portable- 
cpp. html . 

• Non usate i template 

• Non usate le eccezioni 

• Non usate l'RTTI 

• Non usate la libreria standard del C++, 
incluso iostream 

• Non usate i namespace 

L'intera lista è lunga, ma si traduce più facil- 
mente in: non usate il C++. Il linguaggio risul- 
tante da questa serie di menomazioni è un 
sottoinsieme penoso del C++, al cui confronto 
perfino il GWBASIC splenderebbe di un'aura 
di dignità accademica. 

Liste come questa sono nate più di dieci anni 
fa, quando ancora il C++ si identificava con 
CFront e i compilatori faticavano ad imitarne 
il comportamento, privi di una vera e propria 
standardizzazione. In questa situazione i pro- 
getti che miravano ad una certa compatibilità 
decisero di imporsi pesanti limitazioni, pur di 
facilitare le operazioni di porting. Il C++ veni- 
va visto, più che altro, come un C on steroids. 
Oggi tutto ciò non ha più alcun senso. Un 
compilatore che fatichi ad implementare 
caratteristiche standardizzate da dieci anni, 
come namespace, libreria standard ed ecce- 
zioni è un compilatore scadente, e basta. Per 
"migliorare la compatibilità" è sufficiente but- 
tarlo via e prenderne uno decente. 
Nel C++ moderno il semplice atteggiamento 
dell' "io uso solo le classi, il resto non mi inte- 
ressa" è insostenibile. In particolare, è impos- 
sibile fare a meno di funzionalità come tem- 
plate ed eccezioni: ogni volta che userete la 
libreria standard, o le principali estensioni 
come il Tri, Boost e Loki, le userete implicita- 
mente. 

Vi consiglio, in particolare, di spendere molto 
tempo ad imparare ad usare i template, in 
tutte le loro sfumature, compresa la specializ- 
zazione parziale e qualche base di metapro- 
grammazione: scriverete codice molto più 
riutilizzabile e compatto. (Se volete qualche 
esempio, provate a confrontare il codice di 
Smartwin++ con quello di colossi "vecchio 
stile", come QT e wxWidgets). 
E se proprio volete seguire una lista di cose da 
non fare in C++, questo articolo ve ne offre già 
dieci... 

Roberto Allegra 





L'AUTORE 



Il sito 

www.robertoallegra.it 
contiene l'elenco degli 
articoli pubblicati in 
questa rubrica, con gli 
inevitabili 

approfondimenti ed 
errata corrige degli 
articoli e del codice. 
L'e-mail dell'autore è 
posta@robertoallegra.it . 



http://www.ioprogrammo.it 



Dicembre 2007/ 93 ^ 



094-100:036-041-mobile 30-10-2007 16:32 Pagina 94 



MOBILE T 



Giocare con Windows Mobile 



IL RITORNO DI 
PACKMAN PER POCKET 

SICURAMENTE LA MAGGIOR PARTE DI VOI RICORDANO PACKMAN: IL PUPAZZO SFERICO 
CHE DEVE MANGIARE QUANTE PIÙ PILLOLE POSSIBILI SENZA FARSI CATTURARE DAI 
FANTASMI DI TURNO. IN QUESTO ARTICOLO NE PROGRAMMEREMO UNO PER CELLULARE 



-0- 




LJ CD LJ WEB 

Packman.zip 



^ 



n 




REQUISITI 



■ imi imi imi ^m 

' Conoscenze di base di 
Windows Mobile 



Microsoft Visual 
Studio.NET 2005 e 
Windows Mobile 5.0 
PPCSDK 



lì =J =J =J =1 



Tempo di realizzazione 



Nonostante la costruzione di applicazioni 
per smart device debba tenere conto 
delle limitatezza delle risorse di sistema 
è comunque possibile programmare un videoga- 
me sufficientemente professionale e accattivan- 
te. In particolare il gioco sarà costituito dai 
seguenti elementi: 

1. un Packman animato orientabile 

2. un campo da gioco costituito da un certo 
numero di puntini colorati (le pillole) 

3. quattro pulsanti software ed altrettanti 
hardware che consentono di spostare 
Packman 

4. due punteggi: il primo che si aggiorna mano 
a mano che vengono mangiate le pillole, il 
secondo quando un fantasma tocca 
Packman 

5. un numero via via crescente (a seconda del 
livello) di fantasmi che cercano di catturare 
Packman 

6. più livelli con un crescente grado di difficoltà 

7. effetti sonori. 








PARTICOLARITÀ 
DEL FRONT-END 

Una volta che avete creato un New Project per 
Windows Mobile 5 per Pocket PC, visualizzate la 
Toolbox e inserite i componenti grafici richiesti. 
In particolare un controllo Panel per il campo 
da gioco e alcune PictureBox: una sarà 
Packman, le altre quattro i terribili fantasmi che 
renderanno la vita difficile al protagonista del 
videogame. Per animare Packman è necessario 
introdurre una ImageList per ogni posizione che 
esso deve assumere, ad esempio battezzatele 
come segue: imaAnimaSx, imaAnimaSu, 
imaAnimaDx e imaAnimaGiu. Ognuna deve 
contenere le immagini che trovate nella direc- 
tory PackMan\ Immagini del CD: le sx(n), su(n), 
dx(n) e giu(n). Caricatele in ciascuna proprietà 
Images facendo clic sul pulsante Add a partire 




***** * 

Ifét * vm m * 
n* + * * * ■ * • * « 
W* * » * * * * * * 

******** ■ JL* 

********* Hi* 
» m • ■ • * * 

* **h* ** ** 
+ **¥*** » 



* ■ 



Fig. 1: L'applicazione originale Pacman di Atari. 



Fig. 2: Ecco, invece, Packman mentre viene eseguita 
all'interno dell'emulatore per Pocket PC WM 5.0. 



* 94 /Dicembre 2007 



http://www.ioprogrammo.it 



094-100:036-041-mobile 30-10-2007 16:32 Pagina 95 



Giocare con Windows Mobile 



▼ MOBILE 



-0- 



dalla prima (ad es. sxl, poi sx2 ed infine sx3). 
Siccome dovete animare anche i fantasmini 
avete bisogno di un oggetto ImageList per cia- 
scuno di essi: imaMostrol, imaMostro2 t 
imaMostro3 e imaMostro4. Anche in questo 
caso selezionate le immagini che trovate nel CD: 
le fantaAra(n), fantaRo(n), fantaVer(n) e 
fantaVio(n). Questa volta fate attenzione a cari- 
carle in maniera non consecutiva nelle proprietà 
Images: fate clic sul pulsante Add a partire dalla 
prima per picMostrol e picMostro3, mentre per 
picMostro2 e picMostro4 partite dalla seconda 
fino ad arrivare alla prima (ad esempio la 
sequenza per picMostro2 sarà: fantaAra2, 
fantaAra3, fantaAra4 e fantaAral). In questo 
modo garantirete un'asincronia di movimenti 
delle varie animazioni. 



IL CAMPO DA GIOCO 

La creazione del campo da gioco consiste nella 
definizione delle pillole colorate a disposizione 
del vorace Packman. La prima opzione che viene 
in mente per creare le pillole è quella di utilizza- 
re un controllo come la Label o il Panel, ma deve 
essere scartata subito! Il perché è semplice: la 
definizione di cosi tanti controlli (un centinaio) 
renderebbe estremamente lenta l'applicazione. 
Il modo più semplice e compatibile con ottime 
performance del Pocket PC è quello di utilizzare 
il metodo DrawEllipse della classe Graphics di 
Visual Basic.NET. 

Per procedere in questo modo dovete prima di 
tutto creare due variabili globali: una di tipo bit- 
map {Dim Immagine as bitmap) e l'altra 
graphics [Dim Grafici as graphics). Succes- 
sivamente dovete inserire all'interno dell'evento 
Load della form le righe riportate di seguito: le 
prime due sono necessarie (se abbinate alle 
istruzioni inserite nell'evento Paint di 
panSfondo) per evitare che i pallini scompaiano 
se viene ceduto il controllo ad un altro program- 
ma, mentre l'ultima serve a creare una bitmap 
con sfondo bianco. 

Private Sub PackMan_l_oad(...) Handles MyBase.Load 
Me. Immagine = New 

Bitmap(Me. panSfondo. Size.Width, 
Me. panSfondo. Size.Height) 

Me. Grafici = Graphics. FromImage(Me. Immagine) 
Me. Grafici. FillRectangle(New 

SolidBrush(Color.White),0,0,Me. Size.Width, 
Me. Size.Height) 

pMettiPalliniQ 

End Sub 




Fig. 3: Per iniziare una nuova partita bisogna agire 
sul menu File. 



La procedura pMettiPalliniQ richiamata 
anch'essa nell'evento Load della form serve a 
creare e a posizionare le pillole colorate sul 
campo da gioco. 

Private Sub pMettiPalliniQ 

Dim i, riga, col As Integer 

Dim myPen As Pen 

Cursor.Current = Cursors.WaitCursor 

For col = To 200 Step 20 

For riga = 1 To 200 Step 20 

myPen = fColoraPalliniRandom(myPen) 
For i = To 20 

Me. Grafici. DrawEllipse(myPen, (10 + 

col) + i / 2, _ 

(10 + riga) + i / 2, 10 - i, 10 - i) 

Next 

Next 

Next 

Me. panSfondo. Invalidate() 
myPen.Dispose() 
Cursor.Current = Cursors. Default 
End Sub 





LE REGIOM 

Creare Region serve a 
rendere più ordinato e 
leggibile il codice, 
riducendo i ben noti 
problemi di 
manutenzione. La 
sintassi è #Region 
"Nome regione"... 
#End Region. Le 
sezioni di codice 
riportate al loro 
interno vengono 
compresse e, quindi, 
nascoste. Si consiglia 
di comprendere in una 
Region gli algoritmi 
che hanno logica 
simile oppure che 
svolgono azioni simili 
(ad es. variabili, 
eventi, procedure). 



Fig. 4: Packman a design time. 



http://www.ioprogrammo.it 



Dicembre 2007/ 95 ^ 



094-100:036-041-mobile 30-10-2007 16:32 Pagina 96 



MOBILE T 



Giocare con Windows Mobile 




Come potete vedere sono stati utilizzati tre cicli 
For...Next annidati l'uno nell'altro. Cominciamo 
dal più interno. Esso serve per disegnare 20 ellis- 
si, al fine di creare un cerchio completamente 
colorato. Come anticipato dovete utilizzare il 
metodo DrawEllipse della classe Graphics ed è 
necessario definire la penna per poter disegnare 
le ellissi. Questo metodo grafico ha bisogno dei 
seguenti parametri: 



Private Function fColoraPalliniRandom(ByVal 

myPen As Pen) 
Randomize() 
myPen = New 

Pen(Color.FromArgb(m_Random.Next(255), 
m_Random.Next(255), _ 
m_Random.Next(255))) 



fColoraPalliniRandom = myPen 



End Function 



■€+ 



L'EVENTO 

MNUNUOVO 

CLICK 

Questo evento serve a 
riinizializzare tutte le 
variabili ogni volta che 
si decide di incomin- 
ciare una nuova parti- 
ta. In particolare la Re- 
Dim arRigaCol(183, 
201) azzera il contenu- 
to di tutte le celle della 
matrice, ponendole 
uguali a stringa vuota. 



1. penna colorata myPen 

2. coordinate X e Y per posizionare l'oggetto 
sulla form 

3. dimensioni dell'oggetto 

Ad esempio per creare un pallino rosso senza 
riempimento, posizionato in ascissa 10, ordinata 
12 e con dimensioni pari a 20 per 20 pixel è suffi- 
ciente codificare le due righe che seguono. 

myPen = New Pen(Red) 

Me. Grafici. DrawEllipse(myPen, 10, 12, 20, 20) 




Fig. 5: La finestra di dialogo che permette di inserire 
nuove immagini nel controllo ImageList. 



Per riempire il pallino dovete appunto ciclare 
una ventina di volte riducendo via via il cerchio, 
ossia cambiando ogni volta le sue coordinate: 
questo obiettivo si può ottenere facilmente 
aggiungendo alle coordinate X e Y che consento- 
no di posizionare il primo oggetto (10 e 10), 
rispettivamente il valore della colonna e della 
riga corrente, modificati dai cicli precedenti e 
cioè: For col = To 200 Step 20 e For riga = 1 To 
200 Step 20. Notare che quando ciclate sulla 
variabile col effettuate non 200 loop, ma solo 1 1 
perché è stata impostata la clausola Step che 
impone di procedere di venti in venti. Nel caso di 
riga otterrete, invece, 10 loop perché l'indice di 
partenza è 1. Non è un caso, ovviamente, che le 
colonne siano 11 e le righe 10. 
In questo algoritmo è stata introdotta voluta- 
mente una finezza la colorazione dei pallini in 
maniera casuale grazie alla funzione 
fColoraPalliniRandom riportata di seguito. 



La prima istruzione RandomizeQ consente d'i- 
nizializzare il generatore dei numeri casuali. 
Senza RandomizeQ le chiamate a RndQ genere- 
rebbero sempre la stessa sequenza di numeri e, 
quindi, di colori. La funzione Rnd viene, poi, uti- 
lizzata per generare i numeri random che appli- 
cati al metodo Color. FromArgb ci danno il colo- 
re casuale. 

Ovviamente fColoraPalliniRandom è una fun- 
zione non di VB.NET, ma creata da voi. A questo 
proposito è opportuno ricordare quando si uti- 
lizzano le procedure (Sub) e quando le funzioni. 
Entrambe sono in grado di ricevere uno o più 
parametri in input, ma solo le Function possono 
restituire valori. In questo caso era necessario 
restituire alla procedura chiamante la penna 
colorata myPen. 

Infine l'istruzione Invalidate forza il disegno del- 
l'immagine sul pannello panSfondo, mentre la 
Dispose rilascia tutte le risorse grafiche utilizzate 
dall'oggetto myPen } liberando preziosa memoria 
per il Pocket PC. 

Per concludere questo paragrafo facciamo un 
rapido riferimento alla gestione dei cursori del 
mouse. In situazioni in cui esistono momenti di 
attesa dovuti ad algoritmi particolarmente 
pesanti è importante che visualizzate l'icona di 
attesa (corrispondente alla clessidra in ambiente 
PC). Prima di tali algoritmi dovete uguagliare la 
proprietà Current dell'oggetto Cursor ad un 
valore differente da quello predefinito, cioè a 
Cursors.WaitCursor. In questo modo il cursore 
correntemente visualizzato viene modificato e 
l'applicazione smette di attendere eventi del 







.*_- 



Fig. 6: Le funzioni che gestiscono la creazione delle 
"pillole", il loro colore casuale e la loro cancellazione. 



* 96 /Dicembre 2007 



http://www.ioprogrammo.it 



094-100:036-041-mobile 30-10-2007 16:32 Pagina 97 



Giocare con Windows Mobile ■ ▼ MOBILE 



-e- 



mouse; ciò significa che qualsiasi azione effet- 
tuata sul monitor del Pocket PC o sui tasti 
hardware non ha alcun effetto. Al termine dell'e- 
laborazione non dimenticatevi di reimpostare i 
valori di default con Cursor.Current = 
Cur s or s. Default. 



ANIMARE PACKMAN 

Inserite nel progetto un controllo Timer, caratte- 
rizzato dalle seguenti proprietà: 

• (Name)- tmrAnima 

• Enabled-True (in questo modo il Timer risul- 
ta attivo in fase di esecuzione) 

• Intervalli 50 (frequenza in millisecondi di 
attivazione dell'evento Tick) 

Per rendere più avvincente il gioco dovete fare in 
modo che Packman apra e chiuda la bocca e che 
orienti sempre il volto nella direzione verso cui si 
sta muovendo. 

Per animare Packman dovete inserire nell'evento 
tmrAnima_Tick una variabile ctr definita come 
Static e non Dim: in questo modo ctr mantiene 
il valore anche quando il flusso del programma 
esce dall'evento Tick. Se l'avessimo creata con 
una Dim di fatto non avrebbe mai superato il 
valore 1 e l'animazione non avrebbe mai funzio- 
nato. L'incremento della variabile statica avviene 
con ctr-+l. 

Per fare in modo che le immagini effettivamente 
cambino ogni 150 millesimi di secondo non 
dovete fare altro che uguagliare picPackMan. 
Image (che per default già punta alla prima delle 
tre immagini che creano l'animazione) con i 
fotogrammi contenuti nella ImageList. Inoltre 
per direzionare correttamente Packman dovete 
testare la variabile flgPM } che può contenere 4 
valori necessari per puntare aH'ImageList corret- 
ta: l->sinistra, 2->destra, 3->in basso e 4->in alto. 
Prima dell' If...ElseIf ricordatevi di fare il dispose 
delle immagini per evitare di sovraccaricare 
eccessivamente la memoria del Pocket PC. La 
picPackMan. Image. DisposeQ é, dunque, fonda- 
mentale per evitare errori bloccanti in fase di 
esecuzione. 

Infine se la variabile ctr ha raggiunto il suo mas- 
simo valore, cioè 4, uguagliatela di nuovo a zero 
per ricominciare il ciclo. 

Static ctr As Integer 
Dim totlLl As Integer = 

imaAnimaSx.Images.Count 

ctr += 1 

picPackMan. Image. Dispose() 
If flgPM = 1 Then 'sx 



picPackMan. Image = 

imaAnimaSx.Images.Item(ctr - 


1) 


Elself flgPM = 2 Then 'dx 


picPackMan. Image = 

imaAnimaDx.Images.Item(ctr - 


1) 


Elself flgPM = 3 Then 'giù 


picPackMan. Image = 

imaAnimaGiu.Images.Item(ctr - 


1) 


Elself flgPM = 4 Then 'su 


picPackMan. Image = 

imaAnimaSu.Images.Item(ctr - 


1) 


End If 


If ctr = totlLl Then ctr = 



SPOSTARE PACKMAN 

A questo punto non ci resta che vedere come 
spostare Packman sul campo da gioco. Le opzio- 
ni che si possono fornire sono duplici: o via 
software o via hardware. 

Partiamo dai pulsanti software che avete già visto 
in precedenza: btnSx, btnSu, btnDx e btnGiu. 
Per spostare Packman sullo schermo è sufficien- 
te modificare le coordinate della PictureBox 
picPackMan ogni volta che viene fatto clic su 
uno dei pulsanti. Ad esempio potete definire 
all'interno dell'evento click del pulsante btnSx 
che la proprietà Left (corrispondente all'ordina- 
ta) viene decrementata ogni volta di 20 pixel, al 
fine di spostare verso sinistra Packman. 
Ovviamente dovete preventivamente testare che 
non sia avvenuto lo "sfondamento" del bordo 
sinistro del campo da gioco con la If 
picPackMan. Left - 20 >- Then. In questo 
evento viene ogni volta inizializzato il flag/ZgPM 
che permette all'evento tmr 'Anima _Tick di deci- 
dere quale "volto" dare a Packman. 



Private Sub btnS> 


c_Click(.. 


.) Handles btnSx. Click 


flgPM = 1 


If picPackMan. 


Left - 20 


>= Then 




picPackMan 


.Left = p 


icPackMan.Left ■ 


■ 20 


End If 


End Sub 



L'algoritmo precedente deve essere opportuna- 
mente adattato negli eventi Click degli altri pul- 
santi, tenendo presente la verifica dei limiti del 
campo da gioco e l'incremento o il decremento 
delle proprietà Left e Top. 
Detto questo è più efficiente, tuttavia, utilizzare 
un unico gestore degli eventi Click dei quattro 
pulsanti. Dovete dichiarare una procedura 
btnMuovi_Click che riporta tra parentesi gli 
stessi parametri degli eventi Click dei pulsanti 
cioè ByVal sender As System. Object, ByVal e As 
System.EventArgs; dopo la clausola Handles 




uni muovo 

LIVELLO 

Se in tmrMostro_Tick 
esistono le condizioni 
per passare ad un 
nuovo livello viene 
richiamata la 
procedura 
pNuovoLivello, che 
effettua le 
inizializzazioni 
necessarie per 
procedere. 



http://www.ioprogrammo.it 



Dicembre 2007/ 97 ^ 



094-100:036-041-mobile 30-10-2007 16:32 Pagina 98 



MOBILE T 



Giocare con Windows Mobile 




■€+ 



UTILIZZARE 

IL SOFTWARE 

ALLEGATO 

Come prima cosa 

copiate l'intero 

progetto Packman dal 

CD al vostro PC. Per 

avviarlo all'interno di 

Visual Basic.NET 

entrate nella cartella 

Packman e fate doppio 

clic sul file 

Packman.sln. 







J. i HI 



Fig. 7: Le Region sono particolarmente utili per man- 
tenere ordinato e, quindi, più manutenibile il codice. 



specificate btnSx. Click, btnDx. Click, 
btnGiu.Click, btnSu.Click. In questo modo si 
dichiara di voler utilizzare un unico gestore degli 
eventi e, dunque, non dovranno essere presenti i 
singoli eventi Click. 

Come prima istruzione dovete, poi, specificare 
Dim btnSelezione As Button = CType(sender, 
Button) che serve a definire un pulsante virtuale 
che corrisponde esattamente a quelli creati sulla 
form. Facendo riferimento ad esso si possono 
eseguire tutte le azioni che avremmo eseguito 
sui singoli pulsanti. Nel codice seguente, ad 
esempio, potete notare che per testare qual è il 
pulsante selezionato in un dato momento viene 
testata la proprietà Text. 

Private Sub btnMuovi_Click(ByVal sender As 

System. Object, ...) _ 
Handles btnSx. Click, btnDx. Click, 

btnGiu.Click, btnSu.Click 



Dim btnSelezione As Button 



CType(sender, 

Button) 



If btnSelezione.Text = "SX" Then 



flgPM 



If picPackMan.Left - 10 >= Then 

picPackMan.Left = picPackMan.Left - 20 
Elself btnSelezione.Text = "DX" Then 



flgPM 



If picPackMan.Left + 10 <= 202 Then 

picPackMan.Left = picPackMan.Left + 20 
Elself btnSelezione.Text = "GIÙ"' Then 



flgPM 



If picPackMan.Top + 10 <= 185 Then 

picPackMan.Top = picPackMan.Top + 20 
Elself btnSelezione.Text = "SU" Then 



flgPM 



If picPackMan.Top - 10 >= 4 Then 

picPackMan.Top = picPackMan.Top - 20 



End If 



pMangiaQ 



re consideriamo la procedura pMangiaQ che 
consente a Packman di mangiare le pillole colo- 
rate. Il modo più semplice di fare ciò e quello di 
colorare di bianco i singoli cerchi mano a mano 
che Packman si muove. Il codice, che qui non 
riportiamo, è del tutto simile a pMettiPalliniQ • 



I PULSANTI HARDWARE 

I Pocket PC sono solitamente dotati di alcuni 
pulsanti hardware; sicuramente le quattro frecce 
sono sempre presenti. Bene con VB.NET potete 
programmarle per fare spostare Packman. Per 
fare questo dovete programmare l'evento 
KeyDown della form, testando ogni volta qual è 
il tasto hardware premuto. All'interno di ciascun 
If dovete riportare le istruzione per il movimen- 
to di Packman. Infine dovete fare una chiamata a 
pMangiaQ. 



Private Sub PackMan 


_KeyDown(...) Handles 

MyBase. KeyDown 


If (e.KeyCode = Keys.Left) Then 


flgPM = 1 


If picPackMan.l 


_eft - 20 >= Then 




picPackMan 


Left = picPackMan.Left - 


20 


End If 


Elself (e.KeyCode 


= Keys.Right) Then 






Elself (e.KeyCode 


= Keys.Down) Then 






Elself (e.KeyCode 


= Keys.Up) Then 






End If 


pMangia() 


End Sub 



End Sub 



MUOVERE I FAIUTASMINI 

Un videogioco senza ostacoli non è un vero 
videogioco. Ecco perché è importante la presen- 
za dei fantasmini, che se "acchiappano" 
Packman registrano una penalità nel punteggio 
rosso. Le regole che abbiamo inventato sono le 
seguenti: 

• esistono quattro livelli successivi, dove i fan- 
tasmi aumentano sempre di uno fino ad arri- 
vare a quattro nell'ultima barriera. 

• Se Packman viene mangiato quattro volte 
(20.000 punti rossi) il gioco finisce. 

• Ad ogni cambio di livello il punteggio verde 
s'incrementa sempre, mentre quello di destra 
si azzera ogni volta. 



Prima di passare all'esame dei pulsanti hardwa- Inserite nel progetto un controllo Timer, caratte- 



* 98 /Dicembre 2007 



http://www.ioprogrammo.it 



094-100:036-041-mobile 30-10-2007 16:32 Pagina 99 



Giocare con Windows Mobile ■ ▼ MOBILE 



-e- 



rizzato dalle seguenti proprietà: 



• (Name)- tmrMostro 

• Enabled-True (in questo modo il Timer risul- 
ta attivo in fase di esecuzione) 

• Interval-800 (frequenza in millisecondi di 
attivazione dell'evento Tick) 

Ciascun fantasmino viene fatto muovere casual- 
mente all'interno del campo da gioco grazie alla 
procedura pMuoviMostro che riceve come para- 
metro di input la PictureBox corrente picMostro 
e che viene richiamata nell'evento Tick di 
tmrMostro tante volte quante necessarie dal 
livello corrente. 

Private Sub p Muovi Mostro (By Val picMostro As 

PictureBox) 
picMostro. Visible = True 
Randomize() 

picMostro.Top = Int((192 * RndQ) + 0) 

picMostro. Left = Int((2Q8 * RndQ) + 0) 

If (picPackMan.Top <= picMostro.Top + 25 And 
picPackMan.Top >= picMostro.Top - 25) And _ 
(picPackMan.Left <= picMostro. Left + 25 
And picPackMan.Left >= picMostro. Left - 25) Then 
lblPunti2.Text += 5000 
pSuona("Ghost") 

End If 

End Sub 



Successivamente vengono calcolate le coordina- 
te per posizionare il fantasmino in una posizione 
casuale del campo da gioco. A questo proposito 
vengono utilizzate le due funzioni Randomize()> 
per inizializzare il generatore di numeri casuali, e 
RndQ che individua un numero a caso tra zero e 
192, nel primo caso, e un altro tra zero e 208, nel 
secondo caso. 

Infine dovete accertare se le coordinate correnti 
del fantasmino coincidono in parte o completa- 
mente con quelle di Packman. Se la Ifè verificata 
potete aggiungere 5.000 punti come penalità. 
Il cambio di livello e la fine della partita, vengono 
controllati sempre nell'evento Tick di tmr 
Mostro. 

If lblPunti2.Text = 20000 Then 

pulsantiHW = False 

pFine(Chr(13) & "GIOCO FINITO " & 

Chr(13) & Chr(13) & "Raggiunto " & 
Chr(13) & "il numero massimo delle" &_ 
Chr(13) & " penalità -> 20000!") 



pl\luovoLivello("TERZO", 3) 



Elself IbIPuntil.Text = 49500 And livello 



Elself IbIPuntil.Text = 



16500 And livello = 1 

Then 



pNuovol_ivello("SECONDO", 2) 



3 
Then 



pNuovol_ivello("QUARTO", 4) 



Elself IbIPuntil.Text 



66000 And livello = 4 

Then 



pFine(Chr(13) & "GIOCO FINITO " &_ 
Chr(13) & Chr(13) & "Complimenti " & 

Chr(13) & "hai totalizzato il" &. 

Chr(13) & " M A S S I M O !!!") 
End If 



ANIMARE I FAIUTASMINI 

Mentre il movimento di ciascuno fantasmino 
avviene grazie alla sub pMuoviMostro, è la 
pAnimaMostro che si cura di visualizzarne l'ani- 
mazione. 



Private Sub pAnimaMostro(...) 


Dim totMostri As Integer = 

imaMostro.Images.Count 


ctrM +=1 


picMostro. Image = 

imaMostro.Images.Item(ctrM ■ 


■ 1) 


If ctrM = totMostri Then ctrM = 


End Sub 



Elself IbIPuntil.Text = 33000 And livello 



2 
Then 



Al solito le varie immagini sono presenti in appo- 
site ImageList. L'alternanza tra un'immagine e 
l'altra viene "comandata" nell'evento Tick di 
tmrAnima dove, a seconda del livello, viene 
richiamata una o più volte la pAnimaMostro, 
passandole i seguenti parametri: 

• la PictureBox del fantasmino che si vuole ani- 
mare. 

• La ImageList che contiene i fantasmini da 
visualizzare in successione. 

• Un contatore che tiene conto dell'immagine 
corrente. 



EVENTI SONORI 

Al fine di rendere più piacevole il gioco sono stati 
introdotti alcuni suoni: Start.wav che segnala l'i- 
nizio di ogni partita, Mangia.wav che evidenzia 
la mangiata di ogni singola pillola da parte di 
Packman ed, infine, Ghost.wav che viene esegui- 
to quando un fantasmino ha divorato Packman. 
Per eseguire i file wav dovete utilizzare una delle 
funzioni API che Windows Mobile ci mette a 
disposizione. 

La funzione Play Sound deve essere dichiarata in 
un apposito modulo di classe. Scegliete, dunque, 
dal menu File-Add New Item, fate clic su Class e 




http://www.ioprogrammo.it 



Dicembre 2007/ 99 ^ 



094-100:036-041-mobile 30-10-2007 16:32 Pagina 100 



MOBILE T 



Giocare con Windows Mobile 




■€+ 



DISTRIBUIRE 
L'APPLICA- 
ZIONE 

Per distribuire 

l'applicazione, una 

volta ultimata, copiate 

il file PackMan.exe, 

presente in 

PackMa n\bi n\Re lease, 

all'interno del PPC. 

Inoltre dovete anche 

copiare nel percorso 

del Pocket PC \My 

Documents\My Music i 

file audio Ghost.wav, 

Mangia.wav e 

Start.wav. Nessun 

altro file sarà 

necessario perché 

Windows Mobile 

contiene già tutte le 

librerie indispensabili 

al funzionamento 

delle applicazioni .NET. 



nella finestra che appare date un nome alla clas- 
se nel campo Name, ad esempio eseguiWav. 
Successivamente fate clic sul pulsante Open. 
La Play Sound è una funzione nativa del sistema 
operativo (una cosiddetta API, Application 
Program Interface) ed è presente in un file ester- 
no che deve essere referenziato. Per fare ciò 
dovete prima aggiungere un'istruzione di 
Import anteponendola alla dichiarazione della 
classe e, poi, un riferimento [Declare] alla DLL 
che contiene la Play Sound nel Pocket PC, ossia 
Coredll.dll. 

Imports System. Runtime.InteropServices 
Public Class eseguiWav 

Declare Function PlaySound Lib "coredll.dll" (...) 

As Boolean 
End Class 

Di seguito viene riportata la funzione pSuona 
utile ad eseguire i file wav che avrete preventiva- 
mente copiato nella cartella \My Documents 
\My Music del Pocket PC. 

Private Sub pSuona(ByVal pWave As String) 
Dim Suono As String = "\My Documents\My 

Music\" & pWave & ".wav" 
Dim mioWav = eseguiWav.PlaySound(Suono / 

IntPtr.Zero, 1) 
End Sub 

Basterà passare il nome del file sonoro (senza 
estensione .wav) alla pSuona per ottenerne l'e- 
secuzione immediata. 



IL PUNTEGGIO 

Mentre le penalità sono piuttosto semplici da 
assegnare, perché si tratta semplicemente di 
verificare una coincidenza di coordinate e, poi, 
d'incrementare il punteggio rosso, i punti verdi 
richiedono maggiore impegno per la loro identi- 
ficazione. Questo perché non potete semplicisti- 
camente aggiungere un certo punteggio ad ogni 
spostamento di Packman, ma solo quando que- 
sti ha effettivamente mangiato una pillola. 
Vanno dunque esclusi gli spostamenti su spazi 
ormai bianchi. Come fare? Il modo più semplice 
sembra essere quello di utilizzare una matrice a 
due dimensioni, la arRigaCol, che dichiarate 
nella Region delle variabili come Dim 
arRigaCol(183, 201) As String. 
La arRigaCol inzialmente contiene solo spazi 
vuoti, ma nella funzione fPunti imposta la casel- 
la corrispondente al pallino mangiato con una X, 
se la casella stessa è vuota, se cioè in precedenza 
il pallino non era già stato mangiato. 



Private Function fPunti() As Boolean 
Dim flgEsci As Boolean 
If arRigaCol(picPackMan.Top - 1, 

picPackMan.Left - 1) = "" Then 
arRigaCol(picPackMan.Top - 1, 

picPackMan.Left - 1) = "X" 

IbIPuntil.Text += 150 

flgEsci = True 

End If 

fPunti = flgEsci 
End Function 

Ad ogni spostamento la If verifica se la casella 
corrispondente della matrice è ancora vuota, in 
questo caso oltre ad impostare la X, incrementa 
il punteggio e imposta il flgEsci a True per indi- 
care alla sub chiamante pMangia, che devono 
essere fatte certe operazioni. 
La fPunti viene richiamata dalla procedura 
pMangia, a sua volta invocata ad ogni movi- 
mento di Packman, che è stata opportunamente 
modificata rispetto a quella della puntata prece- 
dente. 

Private Sub pMangia() 

If fPuntiQ Then 

Dim i As Integer 

Dim myPen As New Pen(White) 

pSuona("Mangia") 

For i = To 20 

Me. Grafici. DrawEllipse(myPen, 

(picPackMan.Left + 6) + i / 2, _ 

(picPackMan.Top + 6) + i / 2, 20 - i, 

20 - i) 

Next 

myPen.Dispose() 

End If 

End Sub 



E' stato introdotto un test sulla funzione fPu nti 
che rilascia True se la casella corrispondente allo 
spostamento appena effettuato da Packman è 
vuota. In questo caso viene eseguito il file audio 
Mangia.wav e, poi, si procede alla cancellazione 
del pallino. Se fPunti rilascia False non viene 
fatto nulla. 




Fig. 8: La partita è finita, Packman è stato "mangia- 
to" più di quattro volte! 



► 100 /Dicembre 2007 



http://www.ioprogrammo.it 



102-106:072-080 30-10-2007 16:34 Pagina 102 



Sistema T H Errori di aliasing 



IL PATTERN 
VALUE OBJECT 

GLI ERRORI DI "ALIASING" SONO TRA LE CAUSE PIÙ COMUNI DI BUG INSIDIOSI NELLA 
PROGRAMMAZIONE A OGGETTI. UN PATTERN SEMPLICE MA IMPORTANTE DI NOME VALUE 
OBJECT CI AIUTA AD ELIMINARLI DEFINITIVAMENTE. 



-0- 




fri n. ^ 

Q CD □ WEB 


value_object_codice.zip 





n 




REQUISITI 



J Programmazione a 
oggetti 



Qualsiasi linguaggio 
di programmazione 
object-oriented. 



Tempo di realizzazione 



i 



" mmagina un bravo programmatore, che dor- 
me tranquillo dopo una giornata faticosa. Il 

.nuovo sistema di gestione dei conti corren- 
ti è andato in produzione il giorno prima. Trat- 
tandosi di un sistema critico, l'azienda ha de- 
ciso di sperimentarlo in una sola filiale della 
banca che l'ha commissionato. 
Durante la notte, il direttore della filiale butta 
giù dal letto il capoprogetto. Pare che i soldi dei 
nuovi conti correnti stiano misteriosamente 
svanendo nel nulla. A volte succede anche il 
contrario, e alcuni conti si ritrovano con più sol- 
di del dovuto. Il problema è talmente spettaco- 
lare che sarebbe quasi divertente, se non fosse 
che le banche (poco abituate a tirare fuori sol- 
di di tasca propria) sono completamente prive 
di senso dell'umorismo. 

Così il capo chiama il bravo programmatore e 
lo scongiura di correre in ufficio prima del can- 
to del gallo e risolvere il problema. 



MONEY, MONEY 
MONEY 

Ancora in pigiama, il nostro eroe osserva il co- 
dice del sistema. È scritto in Ruby, ma vi spie- 
gheremo quanto basta per capirlo anche se non 
conoscete questo linguaggio. 
La classe fondamentale del sistema è, come ci si 
potrebbe aspettare, quella che rappresenta i 
soldi. Ecco le prime righe della classe: 



class Money 


attr_reader 


:cents 








def initialize(euros, 


cents 


= 0) 


@cents = 


euros * 


100 + 


cents 


end 







dettaglio, a meno che non vogliate diventare 
programmatori Ruby. L'importante è che vi fac- 
ciate una buona idea di come funziona Money. 
Money rappresenta internamente il denaro co- 
me un numero intero di centesimi, conservato 
in un campo @cents (il prefisso @ in Ruby indi- 
ca i campi di un oggetto) . Visto che Ruby è un lin- 
guaggio dinamico, non c'è bisogno di dichiara- 
re il tipo di @cents: basta assegnarli un valore. 
Il valore iniziale di @cents viene assegnato nel me- 
todo initializeO, che è l'equivalente Ruby di un 
costruttore. initializeO prende il numero di Eu- 
ro e quello di centesimi, e converte tutto in un 
singolo numero che rappresenta i centesimi. Il 
numero di centesimi è opzionale: se initializeO 
viene chiamato con un solo argomento, i centesimi 
assumono il valore zero per default. 



QUESTIONE 
DI 



La prima riga della classe Money definisce un 
attributo in sola lettura di nome cents. Per le 
convenzioni di Ruby, questo attributo restitui- 
sce il valore del campo con lo stesso nome, 
@cents. Ecco un semplice esempio: 

price = Money.new(l, 30) 
puts price. cents 

Queste due righe di codice creano un oggetto 
di classe Money inizializzandolo con 1 Euro e 
30 centesimi. In Ruby gli oggetti si creano at- 
traverso il metodo newO, che a sua volta chiama 
initializeO. Il tutto viene convertito interna- 
mente in 130 centesimi, e puts (equivalente 
Ruby di print) stampa questo valore sullo scher- 
mo. 
Vediamo il resto della classe Money: 

def class Money 







Cerchiamo di capire questa classe un metodo 
alla volta. Non è necessario che capitate ogni 



► 102 /Dicembre 2007 



http://www.ioprogrammo.it 



102-106:072-080 30-10-2007 16:34 Pagina 103 



Errori di aliasing ■ T Sistema 



def add(other_money) 



@cents += other_money.cents 



end 



def sub(other_money) 



@cents -= other_money.cents 



end 



def to_s 



return "#{@cents / 100},#{@cents % 1QQ}€" 
end 

I metodi addQ e subQ prendono un altro Mon- 
ey e rispettivamente aggiungono o sottraggono 
i centesimi del secondo oggetto a quelli del- 
l'oggetto ricevente. Il metodo to_s() restituisce 
invece una stringa che rappresenta l'oggetto. 
Questo metodo viene chiamato ad esempio 
quando si stampa un oggetto sullo schermo con 
puts. In questo caso il metodo restituisce una 
stringa che mostra il numero di centesimi divi- 
so per cento (gli euro) e il numero di centesimi 
modulo cento (i centesimi). Vi risparmiamo i 
dettagli sulla formattazione di stringhe in Ruby 
per passare subito ad un piccolo test: 



account = Account. new("Gino", Money.new(100, 

25)) 

puts account 

E il risultato è: 

Gino possiede 100, 25€ 

Sembra che vada tutto bene. Come è possibile 
che due classi così semplici nascondano dei 
bug? Eppure il bug esiste, e non ci resta che cer- 
carlo nel codice che gestisce l'apertura dei con- 
ti correnti. 



IL MISTERO 

DEI SOLDI FANTASMA 

Il codice che apre un conto corrente ha una lo- 
gica simile a questa: 

INITIAL_DEPOSIT = Money.new(lOO) 
accountl = Account. new("Franco", 

INITIAL_DEPOSIT) 

account2 = Account. new("Piero", 




-e- 



m = Money.new(2, 50) 



puts m 
Il risultato è: 

2,50€ 

La classe Money è tutta qui, e non sembra che con- 
tenga alcun bug. Passiamo alla classe Account, 
che rappresenta un conto corrente: 

class Account 
attr_accessor : money 

def initialize(owner, money) 

@owner = owner 
@money = money 
end 

def to_s 

"#{@owner} possiede #{@money}" 
end 
end 

Accountha due campi: un proprietario (@own- 
er) e un importo di denaro {@money) y che è an- 
che accessibile attraverso l'attributo money. 
Possiamo creare un account passandogli una 
stringa per identificare il proprietario, e un im- 
porto iniziale in denaro: 



VALUE OBJECTS IN JAVA E C# 



A differenza di Ruby, dove ogni 
variabile è un riferimento ad un 
oggetto, Java e C# hanno il 
concetto di "variabile primitiva". 
Le variabili primitive non sono 
oggetti, ma tipi semplici come int 
o float. Queste variabili sono 
automaticamente "valori". Ad 
esempio, non potete cambiare il 
numero 1: potete solo usarlo in 
espressioni aritmetiche per 
ottenere altri numeri. In 
linguaggi come questi, il 
problema dell 'aliasing sorge solo 
quando si usano riferimenti ad 
oggetti. 

Un Value Object deve essere 
immutabile, quindi è bene che i 
suoi campi siano delle costanti. 
Ruby definisce i riferimenti 
costanti con una convenzione (la 
prima lettera del loro nome è 
maiuscola). Altri linguaggi 
richiedono invece una parola 
chiave: Java usa final e C# usa 
const. Se dichiarate un 
riferimento final o const, non 
potete più cambiare l'oggetto a 
cui punta quel riferimento. Ma 
attenzione: come in Ruby, il fatto 
che un riferimento sia costante 
non significa che l'oggetto a cui 
fa riferimento sia costante. Per 



assicurarvi che un oggetto sia 
immutabile, verificate che i suoi 
campi siano variabili primitive o 
riferimenti costanti ad oggetti 
immutabili. Notate anche che 
molti dei tipi più usati in questi 
linguaggi, come String o Date in 
Java, sono già immutabili - quindi 
potete tranquillamente usarli 
come campi dei vostri Value 
Objects. 

I Value Object hanno di solito un 
operatore di confronto che 
confronta i valori di due oggetti 
anziché i loro riferimenti. Java 
non ha l'overloading degli 
operatori, quindi non è possibile 
ridefinire l'operatore di confronto 
(==). In Java, questo operatore 
verifica sempre e solo l'identità, 
non l'uguaglianza. Per sopperire a 
questo problema, tutti gli oggetti 
Java hanno un metodo equals() 
che può essere ridefinito e usato 
al posto dell'operatore di 
confronto. I programmatori Java 
imparano ben presto (di solito a 
proprie spese) ad usare equalsO 
al posto di == per confrontare 
tutti gli oggetti, stringhe 
comprese. In questo caso, C# è 
più flessibile e permette di 
ridefinire l'operatore ==. 



http://www.ioprogrammo.it 



Dicembre 2007/ 103 ^ 



102-106:072-080 30-10-2007 16:34 Pagina 104 



Sistema T ■ Errori di aliasing 



-e- 




INITIAL_DEPOSIT) 

Per aprire un conto, si deve versare un deposi- 
to fisso di 100 Euro, che va consegnato in con- 
tanti al funzionario di banca. Quindi il sistema 
definisce una costante che contiene cento Eu- 
ro (in Ruby, un riferimento il cui nome inizia 
con una lettera maiuscola è automaticamente 
una costante). 

A questo punto possiamo scrivere un semplice 
test per verificare cosa succede se Franco, il pro- 
prietario del primo conto, decide di prelevare 
venti Euro: 

accountl.money.sub(Money.new(20)) 
puts accountl 
puts account2 

Il risultato è: 

Franco possiede 80, 0€ 
Piero possiede 80, 0€ 

Orrore! Sebbene Piero non abbia mai prelevato 



PERCHE LA CLASSE MONEY? 



Qualche lettore potrebbe pensare 
che ci stiamo complicando 
inutilmente la vita. Perché 
scrivere una classe Money? Non si 
potrebbe semplicemente usare un 
banale numero in virgola mobile 
per indicare gli Euro? I numeri 
sono già dei Value Objects - anzi, 
in molti linguaggi sono 
semplicemente delle variabili 
primitive, e non essendo oggetti 
non hanno problemi di aliasing. 
Quindi un numero sembrerebbe 
un candidato ideale per 
rappresentare un importo 
monetario. 

Uno dei motivi per scrivere una 
classe Money è che questa classe 
conterrà probabilmente anche 
della logica complessa, come 
quella per le conversioni di 
valuta. Ma anche se non avete 
questo problema, vi conviene 
comunque stare alla larga dai 
numeri in virgola mobile. Ad 
esempio, guardate questo 
programmino che somma 0,99 
Euro per cento volte di seguito: 



money = 


lOO.times do 


money += 0.99 


end 



puts money 

Scrivere lOO.times è un modo 
(piuttosto originale) per ripetere 
un'operazione per cento volte in 
Ruby. L'istruzione puts stampa il 
risultato sullo schermo. Quale 
risultato vi aspettate? Se vi 
sembra ovvio rispondere "99 
euro", provate a far girare il 
programma: 

98.9999999999999 

Abbiamo appena perso un 
decimillesimo di miliardesimo di 
Euro per colpa 

dell'arrotondamento. A parte il 
fatto che la banca riterrebbe la 
perdita inaccettabile ("Qui non 
siamo tipo da buttare via i soldi", 
avrebbero detto), questo risultato 
inatteso scombina anche tutti i 
test, i report e i conteggi di 
verifica. Per questo motivo, 
conviene sempre usare numeri 
interi per rappresentare i soldi. La 
soluzione ideale sarebbe 
probabilmente che il linguaggio 
fornisse già un proprio tipo per 
rappresentare i soldi - ma 
stranamente, quasi nessun 
linguaggio lo possiede. 



soldi dal proprio conto, venti dei suoi Euro so- 
no misteriosamente svaniti nel nulla. A quanto 
pare, ogni volta che uno dei due correntisti ef- 
fettua un'operazione sul proprio conto, l'ope- 
razione viene ripetuta identica anche sul con- 
to dell'altro. Come è possibile? 



PROBLEMI 
DI MEMORIA 

Cerchiamo di capire cosa succede in memoria 
quando i due Account vengono creati. In un lin- 
guaggio a oggetti come Ruby, non si manipola- 
no mai direttamente gli oggetti. Invece, si ma- 
nipolano delle variabili (e delle costanti) che 
sono dei riferimenti agli oggetti in memoria. Ad 
esempio, INITIAL_DEPOSIT è un riferimento 
costante ad un Money. Questo riferimento vie- 
ne passato ai costruttori dei due Account. Ve- 
diamo ancora una volta cosa succede dentro 
ciascun Account: 

class Account 
def initialize(owner, money) 

@owner = owner 

@money = money 
end 



In Ruby, il passaggio degli argomenti e l'asse- 
gnamento avvengono sempre copiando i rife- 
rimenti. Quando chiamiamo initializeO attraverso 
newQ, stiamo copiando il riferimento all'og- 
getto in un argomento di nome money, che su- 
bito dopo viene a sua volta copiato in un cam- 
po di nome @money. Quindi il riferimento vie- 
ne copiato più volte, ma l'oggetto referenziato 
è sempre lo stesso. La Figura 1 mostra la situa- 
zione in memoria: due Account che contengo- 
no ciascuno un riferimento allo stesso oggetto 
Money, che è anche referenziato dalla costante 
INITIAL_DEPOSIT. 



LE COSTANTI 
moni COSTANTI 

Ricapitoliamo: abbiamo creato un Money, lo 
abbiamo referenziato tramite la costante INI- 
TIAL_DEPOSIT e lo abbiamo passato ad Ac- 
count.newQ. Da qui il Money viene passato ad Ac- 
count. initializeO, che lo assegna al riferimen- 
to @money. Lo stesso avviene per il secondo og- 
getto. Quindi, una volta che abbiamo finito di 
costruire gli account, abbiamo tre oggetti che 
referenziano lo stesso Money. 



► 104 /Dicembre 2007 



http://www.ioprogrammo.it 



102-106:072-080 30-10-2007 16:34 Pagina 105 



Errori di aliasing H T Sistema 



-e- 



Quando Franco decide di prelevare venti Euro, 
l'operazione viene delegata all'oggetto Money, 
che sottrae venti Euro da sé stesso. Ma visto che 
i soldi di Piero sono in realtà rappresentati dal- 
lo stesso oggetto che rappresenta i soldi di Fran- 
co, anche Piero scopre con costernazione che 
il suo conto in banca è diminuito. Peggio anco- 
ra: visto che anche il deposito iniziale è un ri- 
ferimento allo stesso oggetto, anch'esso è ora 
diminuito di 20 Euro. Tutti i conti che verran- 
no aperti d'ora in poi conterranno solo 80 Euro: 

account 1. money. sub(Money.new(20)) 

puts accountl 

puts account2 

puts INITIAL_DEPOSIT 

Il risultato è: 

Franco possiede 80, 0€ 



Piero possiede 80, 0€ 



80, 0€ 

Se non avete ancora molta dimestichezza con la 
programmazione a oggetti, potrebbe sembrar- 
vi strano che il valore di INITIAL_DEPOSIT pos- 
sa cambiare. Non avevamo detto che questo ri- 
ferimento è una costante? Ancora una volta, l'e- 
quivoco nasce dalla differenza tra riferimenti e 
oggetti. Visto che INITIAL_DEPOSIT è un rife- 
rimento costante, Ruby protesterà se cerchia- 
mo di assegnargli un oggetto diverso da quello 
con cui lo abbiamo inizializzato. Questo però 
non vuol dire che lo stato dell'oggetto Money 
referenziato non possa cambiare. Se il valore di 
uno dei campi del Money cambia, il povero ri- 
ferimento INITIAL_DEPOSIT non ha nemme- 
no modo di accorgersene. In effetti, questo è 
proprio quello che succede quando chiamia- 
mo il metodo add() dell'oggetto Money 



IL PROBLEMA 
E LA SOLUZIONE 

Problemi come questo sono comuni. Si chia- 
mano problemi di "aliasing", perché derivano 
dal fatto che più riferimenti sono in realtà nomi 
diversi ("alias") per lo stesso oggetto. L' aliasing 
può diventare un problema se perdiamo di vi- 
sta le interazioni tra gli oggetti nel nostro siste- 
ma. Un metodo all'apparenza innocuo può mo- 
dificare l'oggetto che gli viene passato, causan- 
do bug come quello che ha costretto il nostro 
programmatore a correre in ufficio all'alba. 
In molti casi, la soluzione di questo problema è 
semplicemente prestare attenzione agli ogget- 
ti e a chi li modifica. Ma esiste anche un pat- 



tern che può eliminare completamente il pro- 
blema in caso di oggetti come Money. 



IL PATTERN 
VALUE OBJECT 

Un Value Object è un oggetto che obbedisce ad 
un paio di semplici regole. Primo: il suo valore 
non cambia mai. Secondo: due Value Objects 
sono uguali se hanno lo stesso valore. 
Partiamo dalla prima caratteristica. Il proble- 
ma della classe Money è che oggetti diversi pos- 
sono avere riferimenti allo stesso Money. Se uno 
di questi oggetti cambia il Money, anche gli al- 
tri oggetti lo vedranno cambiare. Questo è esat- 
tamente il problema di aliasing che abbiamo 
visto poco fa. Ma se il Money non può cambia- 
re, allora l' aliasing non è più un problema. Gli og- 
getti che non possono cambiare valore si defi- 
niscono oggetti "immutabili". 
Come si fa a rendere immutabile un Money 7 . La 
classe Money è già quasi immutabile: non espo- 
ne proprietà in scrittura, e i suoi campi (come tut- 
ti i campi in Ruby) sono privati. L'unico pro- 
blema sono i metodi add() e sub()> che modifi- 
cano il valore dell'oggetto. Possiamo riscrivere 
questi due metodi perché restituiscano dei nuo- 
vi Money anziché modificare quello esistente: 

class Money 
attr_reader :cents 
def initialize(euros, cents = 0) 

@cents = euros * 100 + cents 
end 
def add(other_money) 

Money.new(0, @cents + other_money.cents) 
end 
def sub(other_money) 

Money.new(0, @cents - other_money.cents) 
end 
def to_s 

return "#{@cents / 100},#{@cents % 100}€" 
end 
end 



Abbiamo omesso la parola chiave return, che 
in Ruby è opzionale. Ora add() e subQ restitui- 
scono un nuovo Money, quindi non è più possibile 
modificare unMojieydopo averlo creato. Que- 
sto significa che dobbiamo anche modificare la 
classe Account per incapsulare completamen- 
te il Money: 




IL LINGUAG- 
GIO RUBY 

Se volete provare 
gli esempi di questo 
articolo sul vostro 
computer, potete 
scaricare il 
linguaggio Ruby 
dal sito 

http://www.ruby- 
lang.org . 

In particolare, se 
usate Windows vi 
consigliamo il One- 
click Ruby Instai ler. 
Quando avete 
installato il 
linguaggio, potete 
lanciare un 
programma con 
il comando: 
ruby nome_del_ 
programma.rb 



class Account 


def initialize 


[owner, 


money) 


@owner = 


owner 




@money = 


money 





http://www.ioprogrammo.it 



Dicembre 2007/ 105 ^ 



102-106:072-080 30-10-2007 16:34 Pagina 106 



Sistema T ■ Errori di aliasing 




-e- 



end 




def add(money) 


@money = @money. 


add(money) 




end 




def sub(money) 


@money = @money. 


sub(money) 


end 




def to_s 


"#{@owner} possied 


e #{@money}" 


end 


end 



Ci siamo quasi. Resta solo da rispondere ad 
un'ultima domanda: quando possiamo dire che 
due Money sono uguali? 



UGUALI E IDENTICI 

Proviamo a confrontare due oggetti Money che 
rappresentano entrambi la somma di 10,15 Eu- 
ro. Usiamo l'operatore di confronto, che in Ruby 
è rappresentato da un doppio "uguale": 

mi = Money.new(10, 15) 
m2 = Money.new(10, 15) 



puts mi 



m2 



L'operatore di confronto non confronta il valo- 
re degli oggetti, ma il valore dei riferimenti mi 
e m2. Dato che questi riferimenti puntano a due 
oggetti Money diversi in memoria, questo co- 
dice stampa/a/se anche se i due oggetti hanno 
valori uguali in tutti i campi. Con tutta probabilità, 
questo non è quello che gli utenti della classe 
Money si aspettano. I soldi sono soldi, e un im- 
porto di 10,15 Euro non è diverso dall'altro. 

Quando abbiamo a che fare con dei valori, ci 
aspettiamo di poter ignorare il concetto di iden- 
tità. Se due Value Object hanno lo stesso valore, 
non ci interessa che siano oggetti diversi in me- 
moria. In Ruby possiamo risolvere il problema 
grazie all'overload degli operatori. Basta ag- 
giungere poche righe di codice a Money per ri- 
definire l'operatore di confronto: 



class Money 


def = = (other) 


return false if other.class ! = 


Money 


return cents = = 


other.cents 




end 







PARTICOLARITÀ 

DEL LINGUAGGIO RUBY 

L'operatore di confronto in Ruby è in realtà un 
metodo che viene chiamato sul primo 
oggetto, passandogli come argomento il 
secondo oggetto. L'implementazione di 
default di ==() restituisce true solo se i due 
oggetti sono identici, cioè se sono 
effettivamente lo stesso oggetto in memoria. 
Noi vogliamo invece restituire true anche se i 
due oggetti sono uguali, cioè se hanno lo 
stesso valore. La prima riga del metodo può 
sembrarvi strana se non conoscete Ruby. In 
questo linguaggio si può mettere l'z/dopo la 
condizione, quindi questa riga si legge: 
"Restituisci false se l'altro oggetto non è di 
classe Money". La seconda riga restituisce true 
o false a seconda che i due importi di denaro 
siano uguali, cioè contengano lo stesso 
numero di centesimi. 

Ora il confronto tra due Money uguali ma non ne- 
cessariamente identici restituisce true. Il no- 
stro bravo programmatore merita di tornare fi- 
nalmente a casa e dormire per il resto della gior- 
nata. 



CONCLUSIONI 

Ricapitoliamo: un Value Object è un oggetto la 
cui uguaglianza dipende dal valore piuttosto 
che dall'identità. I Value Object sono tipica- 
mente immutabili, quindi non hanno proble- 
mi di aliasing. Di solito sono anche "piccoli", 
nel senso che rappresentano quantità semplici 
come un importo di denaro, o una stringa, o 
una data. Niente vi impedisce di scrivere Value 
Objects con dozzine di campi, ma in questo ca- 
so state attenti alle prestazioni: ricordate che 
ogni piccola variazione ad un Value Object vi 
costringe a creare un nuovo Value Object, e crea- 
re migliaia di oggetti molto grossi può essere 
dispendioso. 

Ciononostante, quando scrivete una nuova clas- 
se riflettete sempre sull'opportunità di imple- 
mentarla come un Value Object e risolvere alla 
radice il problema dell' aliasing. 
Come tutti i pattern, il Value Object rappresen- 
ta una soluzione ben rodata ad un problema 
comune. Nonostante che in questo articolo ab- 
biamo usato RUBY per descrivere il problema 
e risolverlo tramite un pattern, in realtà è im- 
portante sottolineare l'importanza dell'algo- 
ritmo rispetto al linguaggio. Con poche modifiche 
il pattern può essere facilmente applicato ad 
ogni linguaggio 

Paolo Perrotta 



► 106 /Dicembre 2007 



http://www.ioprogrammo.it 



108-110:106-108-software 30-10-2007 16:39 Pagina 108 



SOFTWARE SUL CD T Librerie e Tool di sviluppo 



SUL CD 



■O- 



Spices.NET 
Suite 5.2.0.8 

4 PROGRAMMI IN UNO 

La suite raccoglie un obfuscator, un 
decompiler, un modeler e un investiga- 
tor.L'obfuscator consente di "criptare" 
il binario di un codice .NET di modo 
che non sia facilmente possibile disas- 
semblarlo ed ottenerne il codice origi- 
nale. Il decompiler viceversa consente 
di decompilare un software .NET e 
visionarne la struttura. A completare la 
suite due strumenti utilissimi, il primo: 
il modeler consente di progettare il 
proprio applicativo ed il secondo di 
navigarne i metadati. Si tratta una 
suite veramente ben studiata che for- 
nisce al programmatore una base certa 
quando si vogliono integrare o modifi- 
care programmi scritti da altri 
Directory :Rspices. zip 




XAMPP 1.5.5 

IL TUO SERVER PERSONALE! 

Installando questo software avremo a 
disposizione un completo ambiente per lo 
sviluppo di applicazioni web basate su 
PHP e MySQL, ossia una delle piattaforme 
più usate del web. I programmi installati 
saranno: Apache 2.2.3 (server web), 
MySQL 5.0.27 (motore SQL), PHP 
5.20/4.4.4 (linguaggio di scripting), 
phpMyAdmin 2.9.1.1 (tool web per ammi- 
nistrare MySQL), FileZilla FTP Server 
0.9.20 (server FTP), OpenSSL0.9.8.d (libre- 
rie per l'implementazione del protocollo 
SSL). La presenza di un pannello di con- 
trollo, inoltre, semplificherà l'avvio e l'ar- 
resto dei vari server. 
Directory: xampp-win32-1.5.5- 
installer.exe 



PIVOT 1.4.0.4 

IL BLOG CHE AVANZA 

I blog hanno rappresentato e rappresenta- 
no tuttora una delle grandi rivoluzioni 
della rete. La parola d'ordine per ogni blog 
è "semplicità". Semplicità di gestione, di 
installazione, e di utilizzo. Pivot è orienta- 
to in questa direzione ma soprattutto non 
necessita di nessun database di supporto, 
per cui si presta ad essere utilizzato in 
sistemi di hosting a basso costo che non 
offrono db nei loro pacchetti base 
Directory: pivot_1404_full.zip 

DASHCOMMERCE 2.0.1 

IL SISTEMA DI ECOMMERCE 
IN ASP.NET 

Dashcommerce è un ottimo sistema di 
ecommerce scritto completamente in 



.NET e con l'enorme vantaggio di essere 
completamente Free. Il sistema è interes- 
sante e le caratteristiche esposte ne con- 
sentono l'uso anche in fase di produzione. 
La disponibilità del codice lo rende idoneo 
ad essere adattato per moltissime esigenze 
Directory :dashCommerce_2.0. 1.zip 

DOJO TOOLKIT 0.9.0 

IL FRAMEWORK PER JAVASCRIPT 

Javascript dopo un periodo di appanna- 
mento sembra essere tornato alla ribalta 
come motore dello sviluppo di Ajax. 
Questa rinnovata popolarità ha dato il via 
alla nascita di una serie di framework che 
facilitano la programmazione Javascript. 
Fra i tanti spicca dojo. Prima di tutto per la 
sua innata propensione alla programma- 
zione ad eventi, ma anche e soprattutto 
perché consente in una qualche misura di 
utilizzare la tecnologia Ajax in push invece 
che in pop. Ovvero in modo tale che sia il 
server ad inviare i dati al client e non vice- 
versa. In realtà questa possibilità è in via di 
sviluppo e appare soltanto come una delle 
tante tecnologie che Dojo offre ma se 
affiancata a tutto il resto, proprio questa 
caratteristica non è da sottovalutare 
Directory: dojo-release-0.9.0.tar.gz 

DOTLUCENE 2.0 

IL SEGUGIO TROVA TUTTO 

Una delle librerie che ha attratto l'atten- 
zione dei programmatori di tutto il mondo 
nell'ultimo anno è Lucene. Si tratta di una 
libreria che consente di indicizzare in 
modo ottimale il contenuto di un Hard 
Disk per poi poter effettuare delle ricerche 
molto veloci sull'indice. Lucene è stata uti- 
lizzata in progetti di grandi dimensioni 
come ad esempio Beagle. Ne esiste anche 
un porting in ambiente .NET che è appun- 
to quello che vi presentiamo. Utilissima in 
tutti quei casi in cui si vogliano dotare le 
proprie applicazioni di funzioni di ricerca 
"libera" sui contenuti di un supporto o su 



► 108 /Dicembre 2007 



http://www.ioprogrammo.it 



108-110:106-108-software 30-10-2007 16:39 Pagina 109 



Librerie e Tool di sviluppo ■ T SOFTWARE SUL CD 



-0- 



una parte di esso. 
Directory:Lucene.Net-2. 0-002- 
27Nov06.src.zip 

SHARP DEVELOP 2.2.1 

L'ALTERNATIVA A VISUAL STUDIO 

Se siete programmatori C# o VB.NET ma 
non volete utilizzare gli ambienti di 
Microsoft perché troppo complessi per le 
vostre esigenze, SharpDevelop si rivela 
un'ottima alternativa. Si tratta di un 
ambiente leggero, visuale, rad, dotato di 
tutte o quasi tutte le caratteristiche di 
ambienti molto più costosi. Il software è 
completamente opensource. Se credete 
che questo possa essere sinonimo di scar- 
sa affidabilità sappiate che state commet- 
tendo un grave errore. SharpDevelop è 
decisamente un ambiente professionale, 
ben studiato e progettato, inoltre il team di 
sviluppo è particolarmente attivo 
Directory: 
SharpDevelop_2.2.1.2648_Setup.msi 

SPRING 2.0.2 

IL FRAMEWORK DEI FRAMEWORK 

Spring è un Framework che riunisce sotto 
un unico cappello una serie di strumenti 
già esistenti mettendoli ingrando di 
comunicare in modo corretto fra loro. 
Inoltre Spring implementa il pattern Ioc, 
inversion of control che garantisce un alto 
grado di disaccoppiamento e una maggio- 
re manutebilità del codice 
Directory: spring-framework-2.0.2-with- 
dependencies 

PHTML EIUCODER 5.1 

PER CRIPTARE LE VOSTRE PAGINE 
PHP 

Avete necessità di proteggere i vostri script 
PHP da occhi indiscreti? Ecco a voi un 
encoder che vi consente di codificare i 
vostri script prima di distribuirli. Poiché La 
tecnica usata è relativa proprio a PHR i 
vostri script "offuscati" funzioneranno su 
qualunque sistema sia Windows che Linux 
Directory: phtmlenc51.zip 

nunit 2.4.3 

IL COSTRUTTORE DI TEST 

Qualche volta, anzi molto spesso vi tro- 
verete a costruire dei test per "stressa- 
re" la vostra applicazione .NET e vedere 
come reagisce. Nunit è un tool open- 
source che vi mette a disposizione un 
linguaggio per scrivere procedure di 
test. Inoltre consente di visualizzare i 



dati tramite un'interfaccia grafica 
Directory: NUnit-2.4. 3-net-2-0.zip 

DIALOG BLOCK 4.17 

IL RAD PER LE WXWIDGETS 

Da un po' di tempo ormai su 
ioProgrammo ci stiamo occupando di 
wxWidgets. Si tratta di un framework vera- 
mente completo per la costruzione di 
applicazioni c++ multi piattaforma. 
L'orientamento è quello verso la facilita- 
zione della creazione di interfacce grafi- 
che. Nonostante la ricca varietà di compo- 
nenti presenti nel framework mancava 
ancora un tool per creare le interfacce in 
modo RAD. A questa mancanza sopperi- 
sce Dialog Block. Un IDE per lo sviluppo di 
applicazioni basate su WxWidgets e basa- 
to sul modello RAD. E' sufficiente trascina- 
re i componenti sulla form per disegnare 
la propria applicazione. 
Directory: DialogBlocks-4.17-Unicode- 
Setup.exe 

DIA 0.9.5 

CREA DIAGRAMMI DI FLUSSO IN 
MODO SEMPLICE 

Molto spesso nella programmazione di un 
software, o anche semplicemente nell' illu- 
strare il ciclo di vita di un'applicazione o di 
una situazione si fa ricorso a diagrammi di 
flusso. Uno dei leader indiscussi del mer- 
cato in questo settore è senza dubbio Visio 
di Microsoft.Dia non pretende di avere le 
stesse funzionalità di Visio e neanche la 
stessa complessità ma si pone come un 
software leggero diffuso sotto licenza 
OpenSource che può essere usato in modo 
conveniente in tutte quelle situazioni in 
cui è necessario generare un diagramma 
di flusso velocemente 
Directory: dia-0.95-1.tar.bz.2 

EMULE SRC 1.0 

I SORGENTI DI EMULE! 

In questo numero di ioProgrammo abbia- 
mo analizzato il comportamento di una 
rete PHR seguendo passo passo il dia- 
gramma di flusso del programma più 
conosciuto in questo ambito: eMule. Qui 
vi presentiamo i sorgenti del programma, 
che potete analizzare per realizzare un 
vostro client oppure personalizzare secon- 
do le vostre esigenze. Si tratta di un ottimo 
esempio di programmazione, che consen- 
te a molti di apprendere i principi base del 
funzionamento di una rete P2P 
Directory: eMule0.47c-Sources.zip 



NHIBERNATE 2.0 

COME HIBERNATE MA PER .NET 

Neanche .NET sfugge alla logica secondo 
cui i database relazionali sono difficilmen- 
te rappresentabili come oggetti. Ed ecco 
che arriva NHibernate che seguendo lo 
stesso paradigma di Hibernate garantisce 
il mapping fra oggetti ed elementi di un 
database relazionale superando i limiti 
imposti dalle due diverse tecnologie. Il 
tool è particolarmente interessante, sia 
per l'elevato grado di disaccoppiamento 
che offre tra gli elementi del database e le 
classi che lo gestiscono, sia per la capacità 
di trasformare dati tipicamente trattati in 
modo relazionale in classi ed oggetti 
Directory: NHibernate- 1 .2.0.GA.msi 

PBEANS 2.0.2 

PERSISTENZA DEI DATI SENZA 
PROBLEMI 

Pbeans è una libreria scritta in Java che 
consente di implementare la persistenza 
dei dati nelle nostre applicazioni. Grazie a 
Pbeans, normali tabelle, colonne e campi 
di un database relazionale possono essere 
trattati come oggetti e classi, inoltre lo 
stato dell'applicazione può essere salvato 
in un database. Si tratta sicuramente di un 
bel vantaggio. Non ha certo velleità di 
sostituire Hibernate o Castor, tuttavia è un 
buon tool, rapido ed efficiente da usare in 
progetti di dimensioni tali da non giustifi- 
care l'uso di strumenti così complessi 
Directory: pbeans-2.0-2.zip 

FIREBIRD 2.0.0.12748-0 

IL DATABASE VELOCE COME UN 
FULMINE 

Ha attraversato una serie incredibile di 
disavventure. Acquistato da Borland è poi 
tornato ad essere OpenSource. Presente 
sul mercato da tempo immemorabile è 
riuscito a sopravvivere alle sue varie vicis- 
situdine solo grazie alle sue grandi doti 
tecniche. E' un database velocissimo e 
ultraleggero, dotato però di tutte le funzio- 
ni di un server professional 
Directory: Firebird-2. 0.0.1 2748-0- 
Win32.exe 

DADABIK 4.2 

UN CREATORE DI INTERFACCE 
VERSO DATABASE 

Si tratta di una web application scritta in 
PHP che consente di costruire altre web 
application basate su database. Ad esem- 
pio se volete costruire un sito che esponga 



http://www.ioprogrammo.it 



Dicembre 2007/ 109 ^ 



108-110:106-108-software 30-10-2007 16:39 Pagina 110 



SOFTWARE SUL CD T Librerie e Tool di sviluppo 



-0- 



un catalogo multimediale, non vi resta che 
informare Dadabik di quali campi si com- 
pone il catalogo in questione, di quali fun- 
zionalità volete che il vostro sito sia dotato, 
e lasciare a DadaBik il compito di generare 
la vostra interfaccia. Non è necessario 
avere competenze estese di programma- 
zione, l'uso di DadaBik è piuttosto sempli- 
ce. 
Directory: dadabik 4.2. zip 

VISUALWX 087.6 

IL RAD PER LE WXWIDGETS 

Le WxWidgets sono una straordinaria 
libreria che consente di sviluppare 
applicazioni grafiche multi piattaforma 
in C++ con pochissimo sforzo. Unica 
pecca era fino a ieri l'assenza di un 
ambiente RAD per la costruzione delle 
form. Questa limitazione è adesso supe- 
rata, infatti grazie VisualWX è ora possi- 
bile disegnare con pochi colpi di mouse 
la propria applicazione per poi riempire 
di "contenuti" gli eventi associati ai vari 
elementi presenti sulla form. Si tratta di 
una comodità non da poco se si pensa a 
quanto facile sia sviluppare per Win- 
dows e linux contemporaneamente gra- 
zie proprio alle wxwidgets 
Directory: VisualWx_087-60.exe 

THE GIMP TOOLKIT 
2.10.13 

IL TOOLKIT PER LA CREAZIONE DI 
INTERFACCE GRAFICHE 

GTK+ è un framework nato per facilitare la 
creazione di interfacce e basato su compo- 
nenti. Tra le altre cose GTK+ è basato su 
GLIB che rappresenta il core dello sviluppo 
di Gnome. Si tratta di un framework dalle 
caratteristiche piuttosto complesse ma che 
fornisce un supporto completo per lo svi- 
luppo di software usabile e graficamente 
accattivante 
Directory: gtk+-2. 10.13-setup.exe 

WXWIDGETS 2.8.4 

COMODE LIBRERIE PER LO SVILUPPO 
DI INTERFACCE GRAFICHE 

Interessantissime queste librerie, più volte 
le abbiamo utilizzate all'interno di 
ioProgrammo per realizzare degli esempi. 
Si tratta di librerie che consentono la crea- 
zione di interfacce grafiche, possono essere 
utilizzate da C++ ma anche da altri linguag- 
gi come ad esempio Python. La cosa estre- 
mamente interessante è che consentono lo 
sviluppo di applicazioni completamente 



multi piattaforma, sono disponibili infatti 

sia in ambiente unix che in ambiente 

Windows. 

Directory: wxMSW-2.8-4-Setup.exe 

GLUT 3.7 

THE OPENGL UTILITY TOOLKIT 

Facile, intuitivo, performante e solido. 
Queste tutte le caratteristiche che fanno di 
Glut uno dei migliori framework per la 
creazione di interfacce grafiche basate su 
OpenGL.Glut non esporta moltissime fun- 
zioni, ma si concentra sullo sviluppo delle 
interfacce, e consente al programmatore di 
apprendere le basi della programmazione 
OpenGL in modo rapido. E' un ottimo fra- 
mework da utilizzare in tutti quei casi dove 
un'eccessiva complessità rappresentereb- 
be semplicemente un ostacolo allo svilup- 
po 
Directory: glut37.zip 

J2ME POLISH 2.0 

IL COSTRUTTORE DI GUI 
PER DEVICE MOBILI 

J2ME polish è forse un precursore dei 
tempi. Si tratta di un software il cui scopo è 
supportare il programmatore nella creazio- 
ne di interfacce destinate a dispositivi por- 
tatili quali ad esempio cellulari o palmari. 
Ovviamente la base su cui si fonda è J2ME 
ormai onnipresente in qualsiasi applica- 
zione per dispositivi del genere, tuttavia 
invece la definizione dell'interfaccia basa 
le sue caratteristiche su semplici file 
HTML. Interessante è il fatto che 
J2MEpolish sia distribuito sotto licenza 
GPL 
Directory: j2mepolish-2.0-RC.jar 

JAVA SE 
DEVELOPMENT KIT 6 

IL COMPILATORE INDISPENSABILE 
PER PROGRAMMARE IN JAVA 

Se avete intenzione di iniziare a program- 
mare in Java oppure siete già dei program- 
matori esperti avete bisogno sicuramente 
del compilatore e delle librerie Java indi- 
spensabili. 

Sotto il nome di Java SE Development Kit 
vanno appunto tutti gli strumenti e le libre- 
rie nonché le utility necessarie per pro- 
grammare in JAVA. L'attuale versione è la 
6.0 update 3, ovvero la nuovissima release 
densa di innovazioni e molto più legata al 
desktop di quanto non fossero tutte le pre- 
cedenti 
Directory: jdk-6-windows-i586 



ECLIPSE SDK 3.2.2 

L'IDE TUTTOFARE 

Eclipse è un progetto completo portato 
avanti da Eclipse Foundation con la col- 
laborazione di una miriade di aziende 
fra cui IBM, Adobe, Sun e che si è prefis- 
sata lo scopo di creare un IDE estendibi- 
le per plugin adattabile a qualunque 
tipo di linguaggio o tecnologia. Di 
default Eclipse si propone come IDE per 
Java ed è qui che da il meglio di se. Ma 
proprio grazie ai suoi plugin è possibile 
utilizzarlo come ambiente di program- 
mazione per PHP, per C++, per Flex e per 
molti altri linguaggi ancora. Directory: 
eclipse-SDK-3. 2. 1-win32.zip 

PHP 5.2.1 

IL LINGUAGGIO DI SCRIPTING PIÙ 
AMATO DEL WEB 

Sono tre le colonne portanti di Internet: 
PHR APACHE e MySQL. Certo la concor- 
renza è forte. Asp.NET e SQL Server avan- 
zano con celerità, ma a tutt'oggi non si può 
affermare che i siti sviluppati in PHP costi- 
tuiscano la stragrande maggioranza di 
Internet. Quali sono le ragioni del successo 
di cotanto linguaggio? Prima di tutto la 
completezza. PHP ha di base tutto quello 
che serve ad un buon programmatore, 
raramente è necessario ricorrere a librerie 
esterne, Il secondo punto di forza del lin- 
guaggio sta nella sua capacità di poter esse- 
re utilizzato sia in modo procedurale che 
nella sua forma ad oggetti certamente più 
potente e completa. Esiste un terzo di 
punta di forza essenziale che è quello 
riguardante la curva di apprendimento. 
PHP è in assoluto uno dei linguaggi con la 
curva di apprendimento più bassa nel 
panorama degli strumenti di programma- 
zione. 
Directory: php-5. 2. 0-Win32.zip 

MYSQL 5.0.27 

IL PRINCIPE DEI DATABASE 

Indispensabile per programmare web 
application in tecnologia PHP Nonché non 
sia possibile utilizzare altri database, ma 
MySQL e PHP rappresentano veramente 
un binomio inscindibile. L'integrazione fra 
questo database e il linguaggio di scripting 
più usato sulla rete è talmente alta da fare 
divenire quasi un obbligo l'uso congiunto 
di questi due strumenti 
Le ultime versioni inoltre supportano 
molto bene anche Windows 
Directory: mysql-5. 0.27-win32.zip 



► 110 /Dicembre 2007 



http://www.ioprogrammo.it 



lll-114:110-113-Soluzioni mcd 30-10-2007 17:20 Pagina 111, 



Confronto fra testi ■ T SOLUZIONI 



CORRELAZIONE 



TRA TESTI 



NELL'AMBITO DELLA LINGUISTICA MATEMATICA È PARTICOLARMENTE INTERESSANTE 
IL PROBLEMA DEL CONFRONTO TRA TESTI E DELLA CONSEGUENTE VALUTAZIONE 
DI ELEMENTI COMUNI. VEDIAMO COME AFFRONTARLO INFORMATICAMENTE 



-0- 



La vertiginosa espansione della società del- 
l'informazione e della comunicazione pone 
quotidianamente nuove sfide e nuovi proble- 
mi con i quali confortarsi. L'automatica elaborazio- 
ne di testi e la comparsa di internet hanno aumen- 
tato le quantità di dati, in particolare testi da tratta- 
re. Rispetto ai testi si sono intensificate delle attività 
che già in passato si svolgevano e se ne sono pre- 
sentate di nuove. La ricerca di informazioni in scrit- 
ti cartacei in passato era un compito tanto più diffi- 
cile quanto più si aveva a che fare con supporti, 
come registri e libri poco indicizzati e numerosi. 
Oggi la ricerca di informazioni all'interno dei testi 
digitali può contare su tecniche avanzate. Per ricer- 
che all'interno delle nostre personali memorie ci 
sono specifiche routine del sistema operativo; men- 
tre nel vasto mondo di internet si può contare sui 
motori di ricerca. Comunque, anche nell'era digita- 
le cominciano ad essere sempre più numerosi i casi 
in cui tali attività di ricerca diventano difficoltose se 
non impossibili. Altri problemi connessi alla lingua 
sono la tanto invocata traduzione automatica che 
nel corso di molti anni ha registrato notevoli miglio- 
ramenti ma che ancora per alcuni casi presenta evi- 
denti malfunzionamenti. Lo studio grammaticale di 
testi è alla base delle tecniche che esaminano lin- 
guaggi e traduttori, come ad esempio tutto il proces- 
so che porta dalla scrittura di un programma per 
computer alla sua esecuzione. Particolarmente rile- 
vanti sono anche le analisi quantitative della lingua 
che sono alla base di qualsiasi approfondimento 
circa lo sviluppo di tecniche legate alla informazio- 
ne presente in testi. Molto usate sono al proposito le 
tecniche di clustering che sulla base delle informa- 
zioni che si riescono ad estrarre dai testi sono in 
grado di raggruppare e correlare tra loro diversi testi 
rispetto, ad esempio, al loro autore. Insomma, mi 
sembra che sia chiaro quanta energia intellettuale si 
stia convogliando verso la semplice parola, anzi 
anche verso la più elementare lettera, al fine di trat- 
tare una grande quantità di problemi. Nel presente 
articolo dopo aver dato un riferimento generale 
circa la linguistica matematica analizzeremo più da 



vicino un problema concreto in cui si vogliono con- 
frontare due testi, che possono essere due poesie 
tanto quanto due post presi a caso in un forum o su 
diversi forum e verificare se è possibile quantificare 
eventuali attinenze e relazioni tra i due. 



BREVI CENIMI STORICI 

I primi studi concreti sulla lingua risalgono agli 
indiani che si occuparono di analizzare testi da un 
punto di vista grammaticale per meglio compren- 
derli e trasmetterli. Per molto tempo il solo tipo di 
studio è stato di questo tipo. Nel corso degli anni, 
prima che la linguistica si strutturasse come una 
scienza autonoma, gli studi si orientarono in diverse 
direzioni. La prima è la descrizione della lingua in 
determinato periodo della storia in cui si confronta- 
va la lingua scritta con la lingua parlata, le due spes- 
so divergevano tra loro; si introdussero così i primi 
studi di fonetica con una classificazione delle parole 
per suoni che emettevano e con tecniche che li 
riproducevano (come labbiale, gutturale e altri). La 
seconda è un'analisi storica di come si è evoluta, che 
presuppone anche uno studio etimologico sulle sin- 
gole parole. La terza che è di tipo comparativo si 
avvicina maggiormente ai nostri scopi. Soltanto che 
storicamente la comparazione riguardava soprat- 
tutto i rapporti tra lingue e dialetti diversi, cosicché 
si svilupparono i primi rudimentali ma strutturati 
studi per la traduzione. Una sintesi degli studi fatti 
nel corso degli anni porta nel primo quarto del seco- 
lo 19mo secolo ad una lavoro sistematico di alcuni 
aspetti della lingua cosicché si possa parlare di lin- 
guistica. Anche se prevalentemente si trattava sem- 
pre di comparare lingue differenti. Si introduce 
anche la fonetica strutturale, ossia lo studio della lin- 
gua attraverso apparecchi, che investiga circa la pro- 
duzione dei suoni e delle loro qualità acustiche che 
non sono mai uguali anche per parlanti della stessa 
lingua, addirittura per lo stesso parlante. La lingui- 
stica strutturale appare con l'importante contributo 
di Ferdinand De Saussure. Egli dà il via ad una nuova 





Basi di 

programmazione e di 
manipolazione di fogli 
di calcolo 



Tempo di realizzazione 



000000 



http://www.ioprogrammo.it 



Dicembre 2007/ 111 ^ 



lll-114:110-113-Soluzioni mcd 30-10-2007 17:20 Pagina 112, 



SOLUZIONI T ■ Confronto fra testi 



-0- 




epoca, introduce l'importante principio secondo cui 
la lingua non è un insieme di elementi bensì un 
sistema in evoluzione dotato di regole, e che bisogna 
perseguire l'analisi di intere strutture e non di singo- 
li elementi tra loro scollegati, anche per questo gli 
studi di questo studioso sono conosciuti come strut- 
turalismo. Un altro importante contributo fu dato 
dalla scuola di Praga con a capo Nikolaj S. Trubeckoj 
dalla quale emergeva come la lingua è un sistema di 
sistemi (fonologico, morfologico e sintattico). 



FONOLOGIA, MORFOLOGIA 



Suddividere un enunciato secondo 
diversi livelli è un problema 
conosciuto come segmentazione. 
L'unità elementare in cui 
suddividere è il fonema. Lo studio 
fatto con l'ausilio di macchine ha 
portato a classificare per ogni 
lingua i vari fonemi. La cosa 
interessante è che se anche una 
stessa persona pronuncia più volte 



la stessa parola lo spettro 
(un'analisi quantitativa) dei singoli 
fonemi non sarà mai uguale. I 
fonemi da soli non hanno 
significato. Lo assumono quando 
sono raggruppati tra loro. L'unità 
minima che abbia significato è il 
morfema. Una parola (o con nuova 
terminologia sintagma minimo) di 
norma è costituita da più morfemi. 



Ciò che è più vicino al nostro mondo è la linguistica 
matematica, ossia gli studi linguistici con metodi 
matematici. Come per molte discipline anche que- 
sta è apparsa in contemporanea all'apparizione e al 
successivo potenziamento dell'elaboratore. I primi 
studi furono dei sovietici. Qui si introducevano ele- 
menti statistici nella struttura di un testo. Concetti 
che da sempre hanno trovato resistenze in campo 
umanistico ma che sono stati molto utili per alcune 
analisi quantitative. Sono così stati introdotti: la teo- 
ria dell'informazione, la traduzione elettronica e 
altri metodi. Si è parlato per la prima volta di entro- 
pia della lingua che misura lo stato di indetermina- 
zione di ciò che nelle lingua è arbitrario. 



SINTASSI 



La sintassi descrive come parole 
sono raggruppate secondo regole 
grammaticali. Per esprimere uno 
stesso concetto esistono diverse 
forme sintattiche, tutte valide. 
L'analisi sintattica secondo uno 
schema tradizionale prevede la 
scomposizione della proposizione 



in parti, la sistemazione di queste 
ultime secondo differenti categorie 
e la dimostrazione di come sono tra 
loro collegate le parti. La sintattica 
strutturale tenta di fare chiarezza 
su alcuni aspetti, ad esempio sul 
numero e l'ordine gerarchico delle 
unità sintattiche di una lingua. 



uni ESEMPIO 
DI ALGORITMO 
DI CLUSTERIMG 

In uno studio, che mi ha visto coinvolto personal- 
mente, è stato dimostrato che in testi, purché di 



significativa lunghezza, l'informazione è contenuta 
anche nelle frequenze delle singole lettere dell'alfa- 
beto. In altri termini è possibile distinguere due 
scritti, o meglio gli autori, semplicemente analizzan- 
do un vettore delle frequenze delle lettere dell'alfa- 
beto degli scritti. Lo studio è stato sviluppato su testi 
della Grecia antica e con tecniche di clustering; sono 
stati individuati gruppi che corrispondevano ai sin- 
goli autori esaminati. In particolare una volta pro- 
dotta l'impronta per ogni testo, ossia il vettore delle 
frequenze delle 24 lettere greche, sono state applica- 
te alcune tecniche di clustering che hanno eviden- 
ziato i gruppi per autore. Tale metodo ha consentito 
anche l'attribuzione di un testo la cui paternità era 
contesa tra più autori. Tecniche geometriche cono- 
sciute come PCA (principal componenti analisys) 
hanno permesso con limitata perdita di informazio- 
ni di proiettare tali impronte che di fatto erano 
descritte in uno spazio a 24 dimensioni (numero di 
componenti del vettore) in uno spazio bidimensio- 
nale di facile fruizione visiva. Anche questo passag- 
gio che come detto prevede una perdita di informa- 
zione ha mostrato il raggruppamento dei testi ridot- 
ti a miseri puntini in diversi e ben distinguibili insie- 
mi o cluster. Questa esperienza insegna che l'infor- 
mazione è contenuta a diversi livelli in un testo. Non 
solo è del tutto plausibile ipotizzare che le unità 
ancora più elementari di informazione rispetto alle 
singole lettere che sono i fonemi contengano anco- 
ra più informazione. Si immagini di poter memoriz- 
zare un testo parlato nei singoli foneni di una perso- 
na. Sicuramente si tratterebbe di un maggiore patri- 
monio informativo delle singole lettere che se 
vogliamo sono una discretizzazione, un appiatti- 
mento su un singolo simbolo, di suoni simili ma 
diversi. Ma come detto anche le sole singole lettere 
contengono informazione sufficiente a distinguere 
ad esempio gli autori. Del resto è evidente che si 
potrebbero distinguere dei parlati per le diverse 
inflessioni della pronuncia. Nel prossimo esempio, 
invece, l'oggetto della nostre attenzioni come unità 
minima informativa sarà la singola parola. 



COMPARAZIONE 
TRA DUE TESTI 

Un problema ricorrente per chi fa analisi quantitati- 
ve su testi presenti ad esempio sul web è mettere in 
relazione diversi scritti come dei singoli post per i 
forum. Verificare se due post abbiano elementi in 
comune e che tipo di relazione possa esserci tra essi. 
Un modo potrebbe essere applicare anche in questo 
caso tecniche di clustering per raggruppare rispetto 
a qualche parametro più testi. Ma tale metodo nel 
caso specifico è da scartare per due ragioni: la non 
significatività dei testi che spesso sono troppo brevi 
e l'impossibilità di avere numerosi testi tali da poter 



► 112 /Dicembre 2007 



http://www.ioprogrammo.it 



lll-114:110-113-Soluzioni mcd 30-10-2007 17:20 Pagina 113, 



Confronto fra testi ■ T SOLUZIONI 



-0- 



sottoporre ad analisi. Si può quindi pensare di svi- 
luppare un procedimento che possa confrontare 
semplicemente due testi sulla base della semplice 
informazione derivante dalla frequenza delle parole. 
Indicando così un indice di relazione o meglio di 
correlazione tra i due testi in questione. 
Ovviamente, tale valore dipenderà dalla presenza di 
parole comuni nei due testi. Saranno definiti due 
indici di relazione tra il primo ed il secondo testo e 
tra il secondo ed il primo che possono anche diver- 
gere. Se, infatti, il primo testo è più breve e contiene 
molte parole presenti anche sul secondo presenterà 
una forte relazione con esso. Viceversa, il secondo 
avrà un grado di relazione minore rispetto al primo 
testo. L'indice sarà normalizzato in modo che possa 
variare tra zero e uno, con l'intendimento che valori 
vicini allo zero indichino deboli relazioni mentre 
valori vicino all'uno forti relazioni. È utile sottolinea- 
re che si tratta di indici che sono stati prodotti sulla 
base di criteri statistici ma che comunque usano 
procedimenti euristici e che quindi possono essere 
migliorati e vanno opportunamente interpretati. Ad 
esempio è impensabile avere relazioni con indici 
vicino all'uno, si verificano in rari casi. Già valori del- 
l'ordine del decimo (0,1) possono indicare gradi 
"significativi" di relazione. Nello sviluppo del meto- 
do sono state opportunamente considerate tutte le 
parole presenti nel testo, anche elementi che 
potrebbero sembrare privi di informazioni come le 
proposizioni e gli avverbi. Infatti, la ripetizioni oltre 
un limite fisiologico di tali parole può essere un ele- 
mento che contraddistingue un testo. Inoltre, si è 
tenuto conto per ogni parola di un determinato 
peso. Si pensi a parole inconsuete che si vogliono 
evidenziare o marcare, come termini usati in ambiti 
particolari come quelli sessuali o estremisti. Dando 
ad esse peso maggiore determineranno maggiore 
rilevanza nell'indice di relazione. Ovviamente, si 
tratterebbe di definire manualmente i pesi delle sin- 
gole parole nel testo. Ma tranne in rari casi tale pro- 
cedimento non è consigliabile essendo tedioso. 
Allora ho pensato di produrre in automatico tali pesi 
utilizzando un dizionario "universale". Non ho 
nozione se ne esista già un lavoro simile, ma penso 
proprio di si. Si tratta di un dizionario, nel nostro 
caso della lingua italiana, costruito analizzando una 
enorme quantità di testi il più eterogenei possibili 
(provenienti da più ambiti come il letterario, lo 
scientifico, lo sportivo, il giornalistico e quant altro) 
che contiene per ogni parola la sua frequenza relati- 
va, ossia la frequenza fratto il numero totale delle 
parole analizzate; il che indica se la parola è comune 
o rara. Quindi si potrebbe pensare di far pesare mag- 
giormente le parole rare. Questo perché due testi 
sono maggiormente in relazione se contengono 
entrambi una parola desueta piuttosto che una 
parola di uso comune. Il peso potrebbe quindi esse- 
re inversamente proporzionale alla frequenza relati- 



va. Detto ciò l'indice di relazione del testo 1 verso il 
testo 2 può essere espresso dalla seguente formula. 



f - 



V ■.-.:■ r, 

Si calcola come il rapporto tra la sommatoria delle 
frequenze relative per i rispettivi pesi rispetto alle 
parole comuni ai due testi e la stessa sommatoria 
rispetto a tutte le parole del testo. Se per assurdo 
tutte le parole presenti nel testo 1 sono anche pre- 
senti nel testo 2 allora i due termini della frazione 
coincidono e l'indice risulta massimo, ovvero 1, in 
tal caso la relazione del primo verso il secondo testo 
è massima. Se, invece, nessuna parola del primo 
testo coincide con il secondo allora in numeratore è 
zero così come il rapporto, la relazione tra i due testi 
è inesistente. 



IMPLEMENTAZIONE 

Nel produrre l'implementazione darò le indicazioni 
per sviluppare l'algoritmo ed un adeguata struttura 
dati e presenterò un esempio sviluppato su foglio di 
calcolo per il calcolo dell'indice di relazione. I due 
testi siano presenti su due file di nome testol.txt e 
testo2.txt, qualora non lo fossero una routine a parte 
potrebbe caricarli ad esempio dai post di interesse 
nei suddetti due file. I passi dell'algoritmo possono 
essere espressi come segue: 

impronta l=caricatesto("testol.txt") 
impronta2=ca ricatestoCtesto2.txt") 
definiscipesi(dizionario, improntai) 
definiscipesi(dizionario, impronta2) 



LEGGI QUANTITATIVE DELLA LINGUA 




La sinonimia, presente in molte 
lingue, se non tutte, è considerata 
da molti un elemento di ricchezza 
della lingua stessa. Infatti, scrittori 
usano le molteplici possibilità nella 
scelta di parole per definire un 
proprio carattere stilistico. Ad ogni 
modo vi sono parole più usate di 
altre. Alcuni studi hanno mostrato 
che le parole più antiche di origine 
latina e greca sono le più usate ma 
anche le più soggette a 
modificazioni ad esempio 
fonetiche. Ma la cosa sorprendente 
è che esistono delle leggi 
quantitative che valgono per molte 
lingue, per alcune di più che per 
altre. Ad esempio se si ordinano in 
un testo molto grande le parole per 
la loro frequenza in modo non 



crescente (ossia dalla più frequente 
alla meno frequente) il numero 
d'ordine in questa lista sarà il 
rango. Bene, il prodotto tra il rango 
e la frequenza al quadrato di tutte 
le parole tende ad essere costante. 
K=r*f *f . Ma esistono molte altre 
relazioni matematiche a cui 
ubbidiscono le produzioni 
linguistiche. Ad esempio l'entropia 
è definita anche in questo ambito 
come grado di indeterminazione ed 
è calcolabile mediante delle 
formule. La quantità di 
informazione è tanto più grande 
quanto maggiore il grado di 
indeterminazione eliminato da una 
certa informazione. Questo segue 
una logica che si riconduce alla 
teoria di Shannon. 



http://www.ioprogrammo.it 



Dicembre 2007/ 113 ^ 



lll-114:110-113-Soluzioni mcd 30-10-2007 17:20 Pagina 114, 



SOLUZIONI T ■ Confronto fra testi 




-0- 



rl2 = compara(improntal, impronta2) 
r21 = compara(impronta2, improntai) 

caricatesto è molto importante poiché deve farsi 
carico di segmentare il testo in unità informative, 
ossia le parole, tenendo conto dei terminali che le 
dividono, che oltre allo spazio sono tutti i caratteri di 
punteggiatura e speciali. Per ogni parola estratta si 
deve verificare che non sia già presente nel vettore 
che si sta caricando. Se è presente si deve semplice- 
mente incrementare il campo relativo alla frequenza 
assoluta (si veda la dichiarazione in C++ proposta 
più avanti), altrimenti si deve inserire in modo ordi- 
nato nel vettore il nuovo valore settando a 1 il valore 
corrispondente alla frequenza assoluta. Terminato il 
ciclo bisogna innescarne un altro per il calcolo delle 
frequenze relative calcolate come frequenza assolu- 
ta fratto numero totale di parole. Si producono così i 
vettori di record indicati con improntai e 
impronta2. Questi sono aggiornati con i pesi relativi 
alle singole parole attingendo ad un dizionario che 
abbia le caratteristiche descritte precedentemente. 
Infine, è possibile calcolare i due indici comparando 
le due impronte e con il procedimento descritto. 
Una plausibile struttura dati C++ è la seguente: 

const int lmax=10000; 
const int maxpar=15; 

struct occorrenza 
{ char *parola; 

int freq, peso; 

float freqr; 

}} 

occorrenza impronta l[lmax],impronta2[lmax]; 
int nl,n2; 



Con ni e n2 reali cardinalità dei due vettori impron- 
ta. La struttura singola prende il nome di occorrenza. 
In Excel è stato simulato un caso reale, ma molto 
semplicistico; si tratta di testi molto brevi che nella 
realtà si dovrebbero evitare poiché mancano di 
significatività. Nel caso specifico vengono usati per- 
ché con un basso numero di parole si può sviluppa- 
re più agevolmente e con più chiarezza l'esempio. 



L'intera tabella che porta al calcolo dei due indici è 
una cattura del foglio excel ed è riportata in figura 1. 
In verde sono riportati i dati relativi al testo 1, men- 
tre in arancio quelli relativi al testo 2, in giallo i pesi. 
Vi sono in esame 64 parole di cui le prime quattro 
sono presenti nel testo 1 con le frequenze descritte. 
Le altre 60 non sono presenti nel testo 1, mentre si 
ritrovano nel testo 2. Delle prime quattro parole le 
prime tre sono anche presenti nel testo 2. Le due 
colonne dei dati delle frequenze si possono ottenere 
con un apposito programma, ad esempio in C++; e 
poi importate in excel. Il foglio di calcolo ha il van- 
taggio di essere facilmente manipolato, in particolar 
modo nella fase di costruzione di una giusta formu- 
la che esprima la correlazione. Si suppone che i pesi 
siano individuati con un dizionario "universale" o 
opportunamente modificati da utenti autorizzati. Le 
frequenze relative si calcolano come rapporto fra le 
frequenze e il totale delle parole del testo di riferi- 
mento. Le frequenze relative comuni frc presentano 
gli stessi valori delle frequenze relative ma si valuta- 
no nel solo caso siano presenti anche nel secondo 
testo. Il prodotto di tale colonna rispetto al peso è 
calcolato nella colonna adiacente. Rispetto a questa 
serie è importante la somma. I due indici si calcola- 
no con la formula prima descritta. Con i dati presen- 
ti si ottiene un risultato degno di attenzione. Il primo 
indice è alto circa 97% mentre il secondo è di circa 
11% che è molto meno ma non va considerato 
basso. È comunque certo che il primo testo ha un 
elevato grado di attinenza con il secondo avendo 
molte parole presenti in esso. Mentre il secondo ha 
solo una bassa percentuale di termini presenti nel- 
l'altro testo cosicché si stabilisce una minore relazio- 
ne. È interessante fare piccoli esperimenti. Se ad 
esempio si fa in modo che il testo più piccolo pre- 
senti tutte le sue parole nel testo più grande, in tal 
caso bisogna portare ad un valore maggiore di zero 
la frequenza assoluta della quarta parola, si vede 
come il primo indice passa a 1, ossia relazione mas- 
sima. Se non si hanno parole comuni si registra zero. 
E così si può sperimentare e verificare come variano 
di due indici. 



i ■ ■■ 

CLXilJ. 
I ip"i_ 
1- ■ ^ ■ I 



u-fl 



ul£_ 



Jil 



\m"\ 11 'Il 
■ r"hl Vi-dl 





j...-*- 


Fi.." .Jj'n 


T 1: T-Xy* - 


c-s^i:?! 


s* 1 "E 1 !:: 




r. .■■:■. .i ,.-h 


i ."iéj j-j- 


lip M4J 



Fig. 1: I due indici di relazione e valori intermedi per effettuare il calcolo 



CONCLUSIONI 

L'ambito che abbiamo appena sfiorato in questo 
numero è davvero vasto. Ciò sarà emerso dalla 
difficoltà palpabile di fare una sintesi della teoria 
ad oggi prodotta. È comunque appassionante 
sviluppare esperimenti e verificare l'enorme 
mole informativa presente in molte forme della 
lingua. Vi aspetto per l'esplorazione di ulteriori 
aspetti legati a tali questioni. 

Fabio Grimaldi 



► 114 /Dicembre 2007 



http://www.ioprogrammo.it