Programmazione.it v6.2
Ciao, per farti riconoscere devi fare il login. Non ti sei ancora iscritto? Che aspetti, registrati adesso!
Info Pubblicità Collabora Autori Sottoscrizioni Preferiti Bozze Scheda personale Privacy Archivio Libri Corsi per principianti Chat Forum
UML e Design Pattern
Recensito da Paolo De Nictolis il 10-09-2007 ore 10:18
Copertina ISBN: 882033657X
Autori: Massimiliano Bigatti
Editore: Hoepli
Lingua: Italiano
Anno: 2006
Pagine: 284 + XX
Allegati: Nessuno
I testi sui design pattern sono ormai legione, dal classico della Gang of Four (GoF) all'apprezzato testo di Fowler sulle applicazioni di classe enterprise, al Metsker, al Larman ed al Nilsson, ai testi in PDF come il Trowbridge o il Cooper, senza dimenticare le risorse on line comprensive di introduzioni in italiano ed in lingua, ed i gruppi organizzati; né potevano mancare le risorse sull'argomento per i paradigmi più alla moda come SOA ed AJAX.

Molti dei tradizionali pattern GoF sono inoltre già disponibili nei principali framework di programmazione. Questo ennesimo libro sull'argomento adotta un approccio diverso da quello tradizionale, reso celebre proprio dal testo primigenio della GoF, di presentare un catalogo tassonomico dei pattern esistenti, ritenuto poco adatto ai principianti. La strada percorsa è invece quella di illustrare la creazione di due applicazioni di esempio, un visualizzatore di file multiformato ed un Sudoku, presentando l'uso dei pattern per risolvere un problema e solo successivamente discutendo la loro utilità in termini generali.

Lo stesso dicasi per l'uso di UML 2.0 nella progettazione, anche se in questo caso l'autore preferisce introdurre brevemente nel primo capitolo i diagrammi principali (class, sequence e package) ed illustrare i rimanenti in un'apposita Appendice. Il secondo capitolo salta a piè pari ogni introduzione teorica, a parte due pagine sulla terminologia, per mostrare subito la realizzazione del visualizzatore di file tramite tre pattern, due creazionali ed uno comportamentale. La scelta di progetto di permettere al visualizzatore di aprire un solo file alla volta porta naturalmente all'implementazione di un pattern Singleton. Su questo celebre pattern la discussione è piuttosto approfondita, mostrando anche le implicazioni dell'aggiunta di funzionalità di passaggio dei parametri e gestione delle eccezioni alla classe di implementazione, mostrando così come, all'atto pratico, la forma base del Singleton è anche quella più semplice ed elegante.

La creazione di un visualizzatore di file, che consenta una semplice estensione mediante una struttura a plug-in del codice per poter visualizzare nuovi tipi di file, richiede l'uso del pattern Dynamic Linkage, la cui caratteristica principale è il disaccoppiamento completo della classe chiamante da quella chiamata. Com'è facile immaginare, questo pattern fa uso della reflection, e l'unico collo di bottiglia in termini di manutenibilità diventa la scelta di un'adeguata struttura di corrispondenza fra tipo di file e visualizzatore da utilizzare. L'implementazione dei singoli visualizzatori passa per quella di una classe astratta, che definisce lo scheletro del sottosistema di visualizzazione, lasciando l'implementazione dei dettagli alle sottoclassi di implementazione concrete.

Viene utilizzato all'uopo un pattern comportamentale di uso assai comune, Template Method, che oltre a favorire il riutilizzo del codice, permette un adeguato impiego delle risorse di progetto: solitamente infatti architetti e sviluppatori esperti definiscono il Template Method, lasciando alle figure junior i dettagli di più basso livello. Spesso peraltro l'implementazione delle classi concrete è, come in questo caso, parallelizzabile. Per usare una frase fatta, questo secondo capitolo varrebbe da solo il costo di copertina. La maggiore difficoltà nell'uso dei design pattern è che li si può anche mandare a memoria, ma ci vuole poi una certa esperienza di sviluppo per capire se e quando applicarli: il capitolo affronta la questione facendo nascere i pattern utilizzati dalle esigenze dell'applicazione. L'implementazione stessa presenta molti punti di possibile miglioramento, chiaramente evidenziati dall'autore, ma la presentazione delle fasi di progettazione del codice mi ha lasciato davvero soddisfatto.

Nel terzo capitolo viene illustrata l'applicazione di esempio per il gioco del Sudoku, che ci accompagnerà fino alla fine del testo, e l'architettura dei package che la compongono. La definizione dell'interfaccia utente passa, manco a dirlo, per l'implementazione di un pattern Model-View-Controller (MVC), sviluppato from scratch senza fare uso di uno dei numerosi framework disponibili. Il capitolo è mediamente lungo, ma concettualmente non difficile da seguire; buona parte delle pagine è occupata dai lunghi listati. Per gli eventi della UI viene illustrato l'uso del pattern Observer (noto anche come publish-subscribe), implementato in maniera nativa dai gestori di eventi di molti linguaggi moderni. Il pattern stabilisce una relazione uno-a-molti fra oggetti in modo che, quando uno di essi cambia stato, tutti gli oggetti dipendenti ne vengano notificati; in questo caso più che negli altri, non avrebbe guastato il classico diagramma UML per l'illustrazione del pattern. Viene discusso infine un altro pattern assai comune nell'implementazione delle interfacce utente, caratterizzate a volte dalla ripetizione di alcune tediose funzionalità. Il pattern Delegate rappresenta una via alternativa, ed in questo caso più elegante, all'ereditarietà per il riutilizzo del codice: i metodi di una nuova classe non fanno altre che richiamarne altri esistenti nella classe riutilizzata.

Il quarto capitolo si occupa della gestione dello stato dell'applicazione. Questa rischia facilmente di diventare un incubo in termini di manutenibilità del codice nelle applicazioni procedurali, ove solitamente ad ogni stato è associata una costante e le transizioni fra stati vengono gestite con poco eleganti if o switch. L'uso del pattern State consente in tal caso, non solo di semplificare il codice, ma anche di rendere esplicite le transizioni di stato, poiché il codice relativo è presente nelle classi stesse che implementano i singoli stati. Per la verità, la creazione (e la condivisione) degli stati passa per un altro celebre pattern creazionale, l'Abstract Factory, che vedremo in azione nel capitolo successivo ed in quello finale, anche se viene accennato alla fine di questo. Ancora, si preferisce non creare un nuovo stato — inteso come oggetto ad esso associato — se esso è già presente in memoria, ma piuttosto riutilizzarlo: un altro pattern, noto come Flyweight. L'autore discute, infine, un'implementazione alternativa del pattern State basata sull'uso di una tabella di gestione degli stati; l'approccio offre una maggiore configurabilità all'utente finale, al prezzo del maggior costo di risorse legato all'accesso alla tabella.

Nel quinto capitolo, l'introduzione delle funzionalità di undo/redo dei comandi del gioco portano all'introduzione di un potente pattern comportamentale, Command. In questo pattern, ciascuna tipologia di azione è rappresentata da una specifica classe; ogni classe conserva il valore precedente del comando in un campo privato, sì da facilitare le operazioni di undo/redo. Il pattern Composite, che permette la composizione degli oggetti in strutture ad albero in modo che le classi client possano trattare gli oggetti individuali e le composizioni di oggetti allo stesso modo, viene invece utilizzato per estendere l'undo/redo alle macro, ovvero a insiemi di comandi. Per svincolare l'algoritmo di creazione di un nuovo schema di gioco dal resto dell'applicazione viene usato il pattern Strategy, che permette di incapsulare una famiglia di algoritmi, rendendoli intercambiabili: al solito, questo facilita l'estensione dell'applicazione con nuovi schemi di gioco e riduce la necessità di codice condizionale.

Il sesto capitolo è una sorta di interludio in cui l'implementazione di una funzionalità minore, la verifica via Web se si possiede la versione più aggiornata del programma, diventa il pretesto per presentare due pattern assai utili per affrontare casi particolari di una certa classe, Special Case e Null Object. Quest'ultimo è un caso particolare di Special Case, che fornisce un surrogato per rappresentare la mancanza di un oggetto di un certo tipo: l'oggetto dà un'implementazione che non fa nulla, con metodi vuoti dell'interfaccia esposta dalla classe principale.

Il settimo capitolo affronta una serie di pattern di peculiare importanza, quelli per l'accesso ai dati, per l'implementazione del codice di salvataggio e recupero delle partite dell'applicazione di esempio. Tre sono i pattern utilizzati: Data Access Object, che permette di astrarre ed incapsulare tutti gli accessi ad una fonte dati (nello specifico, si disaccoppiano le entità di business dalla modalità di persistenza); Memento, che senza violare l'incapsulamento permette di esternalizzare lo stato interno di un oggetto (spesso al fine di recuperarlo in seguito), utilizzato in modo implicito da molti linguaggi moderni per la serializzazione degli oggetti; e Façade, un pattern di uso massivo nella piattaforma .NET, utilizzato per esporre un'unica interfaccia verso sottosistemi complessi. In questo capitolo e nell'ultimo viene fatto un uso maggiore dei diagrammi UML per illustrare il funzionamento dei pattern. La semplicità dei requisiti di progetto — parliamo di una semplice serializzazione/deserializzazione su file di testo di strutture dati non troppo complesse — non permette comunque di apprezzare appieno l'utilità di questi pattern, che si dispiega appieno in realizzazioni architetturali assai più complesse (e potenti) quali il Data Access Application Block (DAAB).

L'ottavo capitolo, dedicato in massima parte ai pattern creazionali (ma anche a qualcuno strutturale), è particolarmente lungo: da solo, copre più di un quinto del libro. L'intero capitolo è devoto ad un unico obiettivo: migliorare le prestazioni, diminuire la complessità, aumentare il riutilizzo del codice nella fase di creazione degli oggetti. Viene presentata una lunga serie di pattern: Lazy Load; Cache Management; Object Pool; Prototype; Abstract Factory, un pattern direttamente legato alla Dependency Injection; Builder. Ad ognuno di questi è dedicato un paragrafo a sé, svincolato dallo sviluppo dell'applicazione di esempio che ci ha accompagnati per tutto il libro, anche se sporadicamente vi si fa ritorno per qualche esempio di codice. Il risultato non è comunque privo di organicità ed in particolare risulta molto utile il diagramma di flusso a pagina 196, che fornisce un criterio di scelta su quale dei pattern presentati utilizzare. Il testo non esaurisce di certo l'ampia casistica dei pattern, riportando però in Appendice B un elenco più completo.
proQuesto libro può essere davvero un'ottima scelta per il programmatore di medio-bassa esperienza che voglia avvicinarsi al mondo dei design pattern senza affrontare la complessità dei testi sacri sull'argomento. La trattazione è semplice e guidata da codice funzionante, senza essere mai banale. L'impostazione didattica è ottima ed anche il costo è relativamente contenuto.
controE' presente un buon numero di fastidiosi refusi tipografici; questo testo meriterebbe una seconda edizione ben più curata. Inoltre, a dispetto del titolo, i diagrammi UML non hanno un peso preponderante nel libro.
Precedente: IBM lancia DB2 Express-C
Successiva: Corso su Ruby: espressioni regolari (2/2)
Copyright Programmazione.it™ 1999-2009. Alcuni diritti riservati. Testata giornalistica iscritta col n. 569 presso il Tribunale di Milano in data 14/10/2002. Pagina generata in 2.008 secondi. Sito ottimizzato per Mozilla Firefox. Powered by Kyron.