Siccome so di rivolgermi ad una community di sviluppatori, più che una overview vi interessa conoscere qualche dettaglio dietro le quinte. Ho quindi deciso di scrivere un secondo post relativo ad Happy Sign che vada ad esplorare un po' più in profondità le classi che stanno dietro a questo freeware che sto sviluppando. Va bene conoscere cosa fa e come funziona un software, però la curiosità non è affatto donna: la curiosità è asessuata, e quindi vediamo di soddisfarla.
Happy Sign ed i suoi layer
Allo stato attuale, Happy Sign è stato suddiviso in 3 layer fondamentali + 1 layer aggiuntivo di supporto per lo unit testing ed il test da console. I layer attualmente definiti sono i seguenti:
- HappySignCore, il core di Happy Sign, quello di cui parliamo oggi
- HappySignServices, insieme di classi trasversali da supporto a tutto l'ambiente
- HappySign, layer di interfaccia utente Windows Forms
Le referenze sono facilmente intuibili: HappySignCore è il livello più basso della gerarchia di oggetti, mentre la UI è il più alto. Tutti gli altri layer (per adesso uno solo) o stanno in mezzo, o comunque sono trasversali, implementando tutta una serie di classi di supporto/utility utilizzate in modo uniforme da chiunque.
Esploriamo la superficie di HappySignCore
Lanciamo un satellite e poniamolo in orbita a circa 20-30 km dalla superficie del layer HappySignCore. Quello che vedremmo è il seguente diagramma, che - come si sa - dà l'idea più di mille parole:
Quelle rappresentate qui sopra sono 4 classi che danno bene o male una visione complessiva dell'object model esposto da Happy Sign. La classe HappySignCore è l'oggetto root, tramite il quale accediamo a tutto il resto: alla collezione di categorie e firme (rispettivamente le proprietà Categories e Signatures), alla directory dei dati nella quale Happy Sign salva tutto quello che ha bisogno, una proprietà read-only che ho chiamato FirstBoot che ci permette di capitare se è il primo avvio di Happy Sign. L'ultima proprietà Settings contiene tutte le impostazioni dell'istanza di Happy Sign, gestite dalla seconda classe inserita nel diagramma qui sopra: HappySignSettings, l'ultima a destra. Una piccola annotazione: questa classe eredita direttamente dalla classe ApplicationSettingsBase del framework .NET, come è giusto che sia. Di conseguenza, ereditiamo tutto quello previsto dalla classe base, in primis il caricamento dei settings ed il loro salvataggio su disco. Il salvataggio viene effettuato nella seguente directory:
C:\Documents and Settings\<username>\Local Settings\Application Data\ByteAdventure\HappySignData
Le proprietà Categories e Signatures
Le due proprietà qui sopra sono proprietà della classe HappySignCore. La prima espone le categorie, la seconda espone le firme. Come sono state implementate? La proprietà Categories è un'istanza della classe CategoryCollection, ed eredita direttamente da una BindingList<CategoryBase>. La proprietà Signatures è un'istanza della classe SignatureCollection, ed eredita direttamente da una BindingList<SignatureBase>. Entrambe queste collection sono riportate sul diagramma qui sopra. Ho deciso di utilizzare la classe BindingList generica, per avere il supporto allo strong-type offerto dai generics, ed inoltre più supporto ad un eventuale data-binding implementato sull'interfaccia utente.
Entrambe queste collection hanno un comportamento intelligente/evoluto. Evitano per esempio che entrino in collection due categorie e due firme con lo stesso nome (senza sollevare exception, semplicemente non accade nulla). Si preoccupano di mantenere sincronizzate le informazioni: se inserisco una firma che appartiene ad una categoria nuova (e che non compare nella relativa collection), questo viene fatto automaticamente. Se cancello una categoria, automaticamente vengono spazzate via tutte le firme associate a quella categoria, che di fatto non potrebbero più esistere. Inserendo queste logiche nel core di Happy Sign, esse si ripercuotono su tutto il resto dell'applicazione, ed inoltre mi verranno mantenute anche nel caso di modifiche sugli altri layers.
La classe SignatureBase
Parliamo adesso del mattoncino che permette ad Happy Sign di funzionare. Questo mattoncino si chiama SignatureBase, ed è una classe astratta dalla quale derivano tutte le altre tipologie di firme che verranno implementate.
L'interfaccia esposta dalla classe SignatureBase è la seguente:
La classe più a sinistra nel diagramma è la classe astratta che ci interessa. Espone le proprietà di cui abbiamo parlato nel post precedente. La classe NormalSignature eredita da SignatureBase, ma non ne specializza in alcun modo il comportamento. Notare la presenza di metodo GetSignatureText, definito come virtual nella classe astratta. Ogni classe derivata ha l'obbligo di implementare questo metodo, che ritorna un oggetto string che contiene la firma vera e propria. Nel caso della classe NormalSignature, il metodo GetSignatureText non fa altro che ritornare il valore della proprietà Text, che contiene la firma.
La classe DynamicSignature, invece, che eredita da NormalSignature, è un po' più complessa, e ne parleremo interamente nel prossimo post.