Pochi giorni fa mi sono imbattuto in alcune linee guida (Guidance) interessanti per sviluppare con WPF e Silverlight. Queste guidance introducono un approcio per affrontare la progettazione e la realizzazione di applicazioni di livello Enterprise includendo al loro interno diversi pattterns di programmazione. L’applicazione di queste guidance permette di realizzare delle applicazioni molto flessibili con un basso accoppiamento e con la possibilità di evolvere le singole componenti in modo indipendentemente ma facilmente integrabili tra di loro; tali applicazioni vanno sotto il nome di Composite Application.
Problematica:
Tipicamente quando si progetta un software ci si trova davanti alla sfida di progettarlo pensando alla sua evoluzione nel tempo in quanto per svariati motivi i requisiti cambiano. E proprio per questo motivo che è importante costruire l’applicazione in modo tale che sia flessibile e facile da modificare o da estendere nel tempo. Ovviamente progettare un software pensando con un occhio di riguardo alla flessibilità diventa difficile in quanto richiede un’ archittettura che cerca di mantenere indipendenti le singole parti di un sistema in modo tale da poter facilitare lo sviluppo il test e gli aggiornamenti senza che le atttività su una singola parte comprometta le altre componenti dell’applicazione.
Soluzione:
Un modo per risolvere le problematiche viste sopra è quello di dividere l’applicazione in componenti che siano poco accoppiate (loosley coupled) inoltre devono essere indipendenti ma che sia facile integrarle tra di loro in una unica applicazione “Shell”. Le applicazioni che sono costruite in questo modo si chiamano “composite application”.
Composite Application
Questo tipo di applicazioni sono molto adatte per una vasta gamma di scenari in cui si utilizzano applicazioni client. Una applicazione di questo tipo può essere sempre usata quando abbiamo dei componenti indipendenti che evolvono nel tempo e che stanno nella stessa UI e che sono correlati tra di loro ma che sono sviluppati da diversi team.
Composite Application Guidance
Esitono quindi delle linee che permettono di aiutarci nello sviluppo di Composite Application e inoltre vi è una libreria (CAL = Composite Application Library) che aiuta gli sviluppatori nell’utilizzare tali concetti. Analizziamo ora i concetti di base per la costruzione di Composite Application che sono stati riportati nella CAL.
-
UI Composition
-
Modularity
-
Container
-
Multi-targeting.
UI Composition
In queto tipo di applicazioni l’interfaccia in genere è popolata da diversi componenti visuali che sono poco accoppiati e che vengono chiamati Views. Una singola view è definita all’interno di un modulo dell’applicazione. Tutte le view si sono raccolte dal un contenitore che si chiama “Shell” come si vede nell’immagine.
Ovviamente le singole view devono essere poco loosley coupled e devono essere generate a run-time. Per fare questo abbiamo bisogno di una particolare architettura che metta assieme più strategie per fornire il risultato desiderato. Le strategie utilizzate sono le seguenti:
Automaticamente con il modello “View Discovery" la CAL mette a disposizione il RegionViewRegistry per questo tipo di implementazione)
Con la programmazione attraverso il modello “View injection” la CAL mette a disposizione il Region Manager e l’interfaccia IRegion)
Le View sono implementate usando “separated presentation pattern” come i modelli: MVP,presentation Model, MVVM in cui si ha una separazione della logica di presentazione da quella di business e quindi vi sono dei moduli “presenter” o “presentermodel” che contengono la logica di presentazione per la view e sono legati durante la composizione.
Il programmatore possiede due modalità per poter progettare la composizione delle view:
View-First Composition: in cui la view viene creata logicamente prima seguita dal presenter dal quale dipende. Questo spiega il perché questo tipo di approcio si sposa bene con il “view discovery” in quanto la view per una particolare “named location” viene creata automaticamente e seguita dal presenter in base alla relazione sul register.
Presenter-First: composition in cui il presenter è creato logicamente prima seguito dalla vista dal quale dipende.
Command Delegation :questo approcio usa il comando come un delegato per la logica di handling che a questo punto può trovarsi su una classe esterna come un presenter, service o un controller. Il comando richiede due metodi:
Execute() che serve per eseguire la logica associata al comando.
CanExecute() che serve per sapere se un comando può essere eseguito o meno.
Command composition: è una variante di quanto visto prima in quanto la logica di gestione è assegnata ad una serie di comandi figli debolmente accoppiati. Questo approcio prevede un metodo per registrare i comandi figli ad un comando padre e in questo caso il metodo CanExecute ritornerà sempre false almeno che tutti i comandi figli non ritornano true. Per la gestione di questa particolare implementazione dei comandi il CAL mette a disposizione due classi la DelegateCommand<T> e la CompositeCommand.
-
Eventing: Generalmente in applicazioni composte come quelle che stiamo trattando i vari componenti quali i presenter, services e i controller risiedono in moduli differenti che spesso devono comunicare tra di loro. Per fare questo utilizzaimo il Design pattern del publisher/subscriber, utilizzato per la comunicazione asincrona fra diversi. In questo schema, mittenti e destinatari di messaggi dialogano attraverso un tramite, che può essere detto dispatcher. Il mittente di un messaggio (detto publisher) non deve essere consapevole dell'identità dei destinatari (detti subscriber); esso si limita a "pubblicare" il proprio messaggio al dispatcher. I destinatari si rivolgono a loro volta al dispatcher "abbonandosi" alla ricezione di messaggi. Il dispatcher quindi inoltra ogni messaggio inviato da un publisher a tutti i subscriber interessati a quel messaggio. Ci sono diversi modi di implementare questo pattern ma per le Composite Application Guidance ne esistono due:
Event Services: Con questo approcio si usano il sistema di gestione degli eventi del .Net framework. Sia il publisher che il subscriber si referenziano alle interfacce del servizio e non dipendono direttamente l’una dall’altra. Con questo approcio il subscriber ha bisogno di gestire manualmente la registrazione e la de-registrazione all’evento prima che sia gestito dal garbage collector.
Event Aggregtion:con questo approcio si usa un event aggregator generico che contiene un repository degli eventi per gli oggetti. Gli eventi degli oggetti usano dei delegati istanziati dal .Net Framework. Il vantaggio di questa tecnica e che i delegati possono essere creati quando si pubblica un messaggio e poi rilasciati senza prevedere un carbage collected da parte dei subbscribers. Ogni oggetto evento contiene una collection di subscribers che riceveranno il messaggio. Nella libreria CAL è disponibile la classe CompositePresentationEvent<T> che permette questo tipo di approcio.