Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

[MCAD.9] OOP e separazione tra la UI e la logica delle applicazioni

Oggi è sabato, sicuramente ci sono meno persone che seguono il blog di UGIdotNET. Per questo motivo volevo un attimo riassumere quello che ho fatto finora e fare delle riflessioni.

  1. Abbiamo creato una piccola applicazione .NET tramite Windows Forms che dice l'età di una persona dato il suo anno di nascita
  2. Sono stati usati l'evento Validating e il controllo ErrorProvider per controllare che l'utente abbia inserito nella TextBox un valore valido
  3. E' stato visto l'utilizzo della Property CausesValidation sui controlli per evitare la validazione sui pulsanti che non la richiedono (help, button di annulla)

L'applicazione funziona e non dà problemi. E allora, qual'è lo scopo di questo post? Lo scopo è quello di fare una riflessione, nè più nè meno. Quello che dirò non riguarda direttamente la certificazione MCAD, ma più in generale riguarda la scrittura di buon codice, un approccio corretto alla OOP offerta da .NET e, perchè no, qualche dritta su come secondo me è possibile veramente riutilizzare del codice che scriviamo.

Ieri sera, al pub con gli amici, davanti ad una birra media rossa, mi è balenata una domanda: "La mia applicazione WF funziona e mi sta bene. Cosa succederebbe se volessi spostare la stessa logica su un sito ASP.NET? Oppure creare un web-service? Oppure, che ne so, ricompilare tutto con Mono per far girare la mia app sotto Linux?". Cosa vi rispondete voi?
Beh, io dico che l'applicazione che ho scritto è orribile: cercate di fare quello che ho appena ipotizzato e scoprirete che probabilmente dovremmo riscrivere buona parte del codice. Pensiamoci un attimo:

  1. la validità dei dati è inesorabilmente cablata dentro l'evento Validating della TextBox: e se un giorno non avessimo più la TextBox, cosa succederebbe? Se avessimo un campo testo in HTML, l'evento Validating non c'è più, sbaglio? E allora?
  2. anche il codice che calcola l'età è legato ad un evento, il Click del btnCalcola. E allora?

La soluzione a tutte queste domande consiste nell'applicare correttamente la OOP come si deve. Cosa vuol dire? Beh, sicuramente siete tutti sviluppatori, quindi non vi stupirà leggere il codice seguente:

public class Age
{

    
private DateTime _BirthDate;

    
public DateTime BirthDate
    {
        
get
        
{
            
return(this._BirthDate);
        }
        
set
        
{
            
this._BirthDate = value;
        }
    }

    
public Age() { }

    
public Age(DateTime BirthDate)
    {
        
this._BirthDate = BirthDate;
    }

    
public int getAge()
    {
        
int age;
        age = System.DateTime.Now.Year - 
this._BirthDate.Year;
        
return(age);
    }
}

La classe Age implementa la logica che abbiamo realizzato nell'applicazione WF. Ovviamente si tratta di una classe molto semplice: ha una sola property BirthDate di tipo DateTime e un solo metodo, getAge, che ritorna un int. Questa classe può essere riutilizzata in ogni tipo di progetto: Windows Forms, web-services, ASP.NET. Probabilmente verrebbe compilata anche sotto Mono.

E' una classe completamente slegata dall'interfaccia utente, che a questo punto può essere qualsiasi cosa, dal Windows Form (come abbiamo fatto noi) su PC o su palmare, all'oggetto Console, addirittura potremmo non avere affatto una UI. Potremmo avere un file di testo contenente 100 anni di nascita diversi, la nostra applicazione potrebbe leggerlo e usare la classe Age per calcolare l'età di ogni persona, e scrivere infine un secondo file di testo con i risultati. Questo tipo di approccio sfrutta al meglio la separazione tra la UI e la logica, che adesso sono completamente slegate fra di loro.

E la validazione, che fine ha fatto? Beh, il concetto che solitamente seguo è questo. Innanzitutto, una piccola premessa: lavorando con Visual Basic 6.0, mi capitava spesso di usare le classi. Le property le definivo dichiarando le variabili pubbliche (ad esempio, Dim BirthDate as Date). Volendo diventare MCAD, e volendo programmare decentemente, certe abitudini bisogna perderle.

Ecco il codice come l'ho scritto io:

private DateTime _BirthDate;

public DateTime BirthDate
{
    
get
    
{
        
return(this._BirthDate);
    }
    
set
    
{
        
this._BirthDate = value;
    }
}

La property BirthDate è definita tramite set e get. La set permette di assegnare al membro privato _BirthDate il contenuto di value. All'interno del blocco set, quindi, possiamo inserire tutti i controlli di validazione che vogliamo: anno < 1800, oppure > System.Date.Now.Year e così via. Cosa succede se la validazione fallisce? Ricordiamoci che lavorando con le classi dobbiamo partire dal presupposto che non abbiamo UI (o meglio, non ne siamo a conoscenza, potrebbe esserci oppure no, chi lo sa?): quindi se qualcosa non è andato a buon fine, dobbiamo in qualche modo comunicarlo al client. Il client in questo caso può essere un sito web, una WF, un altro "pezzo di codice" che proviene dall'altra parte del mondo. Proprio perchè una classe è istanziabile ed utilizzabile indipendentemente dall'architettura del client. Comunque, in breve, se la validazione fallisce, bisogna sollevare un'eccezione (throw), che verrà gestita nel modo più opportuno dal client con un blocco Try...Catch come ho scritto nel mio post precedente. Se avessimo un WF, l'eccezione verrebbe "trappata" da un Try...Catch e verrebbe utilizzata il controllo ErrorProvider come abbiamo già visto.Questa è una cosa importante da considerare, perchè ovviamente non sempre possiamo visualizzare un MessageBox, quindi possiamo e dobbiamo intercettare gli errori e gestirli secondo il contesto in cui ci troviamo. Se stessimo scrivendo un windows service e la classe ci ritorna un errore di qualche tipo, potremmo utilizzare la classe EventLogTraceListener (da studiare per MCAD) per loggare nel registro degli eventi di Windows, per esempio.

Nei prossimi post dedicati a MCAD partiremo quindi sempre con questo concetto in testa: magari per questioni di tempo e velocità scriveremo sempre linee di codice per WF, ma l'approccio migliore e che rende di più è sicuramente quello che si appoggia sulle classi come credo di aver descritto in questo post.

powered by IMHO 1.2

Print | posted on sabato 9 luglio 2005 20:46 | Filed Under [ MCAD ]

Feedback

Gravatar

# [MCAD.10] Finalmente un'applicazione completa, da estendere con la Study Guide

11/07/2005 20:48 | Technology Experience
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET