Introduzione
Sono ormai alcuni anni che Visual Basic.NET è nato dando la possibilità ai " vecchi " programmatori vb 6.0 di
"rivalutars" supportati dalla potenza e la versatilità della programmazione " Object Oriented ". Tutto questo però, ha un costo. Spesso noto una certa difficoltà nell'apprendere la differenza tra tipi riferimento e tipi valore su ciò che accade in memoria quando istanziamo un oggetto o quando creiamo una classe, cosa che in vb 6.0 non preoccupava più di tanto. Sono pochi i manuali che spiegano cosa è una classe in un linguaggio comprensibile anche a chi si avvicina la prima volta alla programmazione OO. Lo scopo di questo articolo è dare delle delucidazioni, senza entrare nel dettaglio, sugli argomenti appena citati, soprattuto a chi non sa niente di programmazione ad oggetti.
(forze sono un pò ambizioso!).
Cos'è una Classe
Spesso sui manuali si parla di classe come la rappresentazione in linee molto generali di una determinata entità. Esempi di classe possono essere libro, persona, automobile, ecc. Prendiamo per esempio la classe automobile.Tutte le automobili sono di un certo colore, hanno delle ruote, magari ce ne sono alcune che ne hanno 18, altre 4 ma hanno pur sempre delle ruote. Tutte possono accelerare, frenare ecc. come lo fanno dipende da come sono costruite. La classe è una specie di progetto , ne delinea i tratti e le caratteristiche salienti, senza entrare nel dettaglio. Quando progettiamo la classe automobile non ci interessa di che colore è, quante ruote possiede, bensì ci interessa sapere se queste sono caratteristiche comuni a tutte le automobili, e se ci interessa rappresentarle per i nostri scopi. Cosa molto importante è che una classe non esiste in memoria, come un progetto non esiste fin quando non lo realizziamo. Quando istanziamo una classe dando vita ad un oggetto e come se realizzassimo un progetto, nel nostro caso e come se costruissimo un automobile. Come l'automobile è stata costruita la possiamo toccare, guidare ecc. così la classe una volta istanziata la possiamo utilizzare, tramite i suoi metodi e proprietà.
I metodi sono le funzionalità che la classe espone, come l'automobile può accelerare e frenare, mentre le proprietà sono le caratteristiche, come un'auto può essere rossa con quattro ruote. Come l'automobile accelera e frena è affar suo, così come "funzionano" i metodi di una classe a noi non interessa basta che funzionano. Può sembrare una battuta ma è molto importante che sia così, ovvero chi utilizza la nostra classe non deve sapere come funziona, deve invece sapere come può utilizzarla. Nel caso delll'automobile quando acceleriamo non ci interessa sapere come la benziana arriva nel motore, e come fa il motore ad utilizzarla per far muovere la macchina, ci interessa invece sapere come accellerare, in questo caso pigiando sull'acceleratore. Il concetto appena espresso è quello che nei manuali viene definito Incapsulamento. Come ho detto prima, non ci interessa come la classe funzioni, ma ci interessa sapere come utilizzarla. Per questo le classi hanno un' interfaccia che ci permette di utilizzare i suoi metodi, tramite i quali ci vengono fornite le funzionalità.
Spero che a questo punto vi siate fatti un'idea di cosa è una classe ora vediamo cos'è un oggetto.
Cos'è un oggetto
Un oggetto, viene definito come l'istanza di una classe. Ma che significa ?
Vuol dire semplicemente che instanziando una classe, è come se costruissimo materialmente il tipo che la classe definisce. Nel caso di prima, un'istanza della classe automobile potrebbe essere la Ford Fiesta 1.3 a benzina di colore grigio metallizzato. La prima differenza che notiamo è che quando parlavo di classe, rimanevo sul generale... "ha delle ruote cammina ecc", invece ora che l'ho materializzata vado sullo specifico... " Ford Fiesta 1.3 a benzina di colore grigio metallizzato". Questo perchè la classe descrive in linee generali un tipo, un oggetto invece è ben definito; in questo caso ho "cretao" un'oggetto automobile avente le seguenti propietà: marca=Ford motore=1.3 Benzina colore=grigio. Questo esempio è servito a far notare un'altra differenza tra classe ed oggetto: l'oggetto oltre ad esistere ed occupare fisicamente memoria, ha uno stato ben definito. Lo stato, in parole molto povere, non è altro che il valore delle proprietà dell'oggetto. Quindi riassumendo, possiamo dire che una classe è un'insieme di entità di quel tipo, l'oggetto è un un elemento ben definito di questo insieme, come la ford fiesta è un elemento dell'insieme automobili (Fig. 1)
Fig. 1
L'oggetto oltre ad avere delle proprietà ha anche dei metodi. I metodi servono a far sì che noi possiamo utilizzare l'oggetto, cambiare il suo stato (modificare il valore delle sue proprietà) ed usufruire delle sue funzionalità. E' molto importante che sia possibile modificare lo stato dell'oggetto, solamente tramite i suoi metodi e non direttamente. Questo è neccessario in quanto, non sapendo il funzionamento interno della classe, potremo far trovare l'oggetto in uno stato alterato e di conseguenza potrebbe non funzionare correttamente. Ecco perchè quando si proggetta una classe è molto importate stabilire quali sono le proprietà che verranno "viste" e fornire i metodi che permettano di modificarle in tutta sicurezza.
Cosa succede in memoria...
Ora, dopo tutta questa bella (non troppo) teoria, vediamo cosa succede fisicamente in memoria quando istanziamo una classe. Penso questa sia la sezione più importante dato che spesso leggo nei forum: come faccio a raggiungere il form X dalla form Y, come posso accedere a quell'oggetto da quest'altro ecc.
Prima di tutto progettiamo una classe per esempio automobile.
Class Automobile
private modello as string
private colore as string
public sub setModello(nome as string)
modello=nome
end sub
public sub setColore(colore as string)
me.colore=colore
end sub
public Function getColore()as string
return colore
end Function
public Function getModello() as string
return modello
end Function
public Function getColore() as string
return colore
end Function
public sub Frena()
console.writeLine("Sto frenando")
end sub
public sub Accellera()
console.writeLine("Sto accellerando")
end sub
End Class
Questa è la classe automobile. Come potete vedere ha due proprietà colore e modello non modificabili direttamente, ma tramite i relativi metodi. Poi abbiamo la funzionalità frena e accelera. Ciò detto vediamo cosa accade in memoria quando creiamo un'istanza della classe.
Prima devo creare una variabile ti tipo riferimento, adatta a puntare l'oggetto automobile che istanzierò.
Con istruzione che segue non ho creato ancora nessun oggetto: non posso accedere alle proprietà ed ai metodi della classe automobile, anche se l'intelliSense di VB.net, purtroppo, li fa vedere già in questo punto come se fossero accessibili.
Dim auto as Automobile
Dopo questa istruzione, l'unica cosa che c'è in memoria è una variabile di tipo riferimento, "adatta a puntare" un oggetto di tipo automobile che ancora non esiste !!!.(Tengo a precisarlo dato che con viasul Basic 6.0 questa differenza non era così evidente, a volte neanche necessaria,basta pensare alle form.)
auto=new Automobile
Analizzando l'istruzione vediamo che è composta da "Auto= " che è la variabile ti tipo riferimento precedentemente dichiarata , poi segue "New Automobile" che crea fisicamente l'oggetto in memoria con tutti i suoi metodi e le sue proprietà restituendo, l'indirizzo di memoria dove è stato creato, alla variabile auto. Ora è possibile accedere all'oggetto, dato che esiste, tramite la variabile che vi punta (Fig 2).
Fig. 2
Ora che l'oggetto è stato creato, non possiamo più distruggerlo e quindi liberare la memoria che occupa. L'unica cosa che possiamo fare è non far puntare più la variabile "auto" all'oggetto "automobile" così verrà distrutto del Garbage Collector (non sappiamo dopo quanto tempo).
auto= Nothing
Così facendo l'indirizzo di memoria dove risede l'oggetto automobile, che era contenuto nella variabile "auto" viene "cancellato", di conseguenza non sarà più possibile raggiungerlo, dato che l'unica variabile che lo puntava, o meglio referenziava, era la variabile "auto". Ho tenuto a precisare il fatto che non c'erano altre variabili di tipo riferimento che referenziavano l'oggetto in quanto, potrei referenziarlo anche con un altra variabile. Per capir meglio quanto spiegato vediamo un esempio pratico:
' creao la variabile riferimento per l'oggetto automobile
dim auto as automobile
'creo l'oggetto e lo faccio puntare alla variabile auto
auto=new automobile
' creo un'altra variabile riferimento per l'oggetto automobile
dim altraAuto as automobile
'copio l'indirizzo di memoria
altraAutomobile=auto
console.writeLine(auto is altraAuto) <-------True
Analizziamo il codice:
La prima parte è come l'esempio precedente ovvero creo la variabile di tipo riferimento "auto", poi creo un oggetto automobile e lo faccio puntare alla variabile "auto". Dopo creo un'altra variabile di tipo riferimento, ma non creo un'altro oggetto automobile, bensì copio l'indirizzo di memoria contenuto nella variabile "auto" nella variabile "altraAutomobile". Quindi ho due variabili di tipo riferimento che puntano allo stesso oggetto (Fig 4).
Fig 3
Volendo verificare che quanto detto corrisponde a verità proviamo il seguente codice
' creao la variabile riferimento per l'oggetto automobile
dim auto as automobile
'creo l'oggetto e lo faccio puntare alla variabile auto
auto=new automobile
'Imposto le proprietà
auto.colore="Grigio"
auto.modello="Ford Fiesta"
'stampo lo stato dell'oggetto
console.writeLine(auto.colore & " " & auto.modello)<-------- Grigio Ford Fiesta
' creo un'altra variabile riferimento per l'oggetto automobile
dim altraAuto as automobile
'copio l'indirizzo di memoria
altraAutomobile=auto
'modifico lo stato dell'oggetto automobile utilizzando un altro puntatore
altraAutomobile.colore="Rosso"
'stampo lo stato dell'oggetto
console.writeLine(auto.colore & " " & auto.modello)<-------- Rosso Ford Fiesta
Come abbiamo visto ho impostato lo stato dell'oggetto usando la variabile riferimento "auto", poi ho modificato il colore utilizzando però l'altra variabile riferimento.
Se ora cancello l'indirizzo di memoria nella variabile "auto" impostandola a "Nothing", l'oggetto è comunque raggiungibile dalla seconda variabile "altraAutomobile" quindi non verrà distrutto. Sono sicuro che nessuno si è accorto che nell'esempio abbiamo utilizzato implicitamente un altro oggetto. Vi starete chiedento dove?
Semplicemente quando abbiamo impostato il colore dell'automobile ed il modello.
Con l' istruzione auto.colore="Grigio" implictitamente il runtime ha istanziato un oggetto String restituendo il riferimento all'oggetto appena creato alla variabile di tipo riferimento "auto.colore". Quindi lo schema precedente diventa:
Conclusioni
Con questa articolo si chiude la prima parte dedicata alle classi ed agli oggetti. Spero che l'articolo abbia chiarito dei concetti che, se pur elementari, difficilmente vengono illustrati dai manuali di programmazione OO. Nella prossima parte continuerò ad illustrare classi ed oggetti entrando poco a poco nel dettaglio, facendo continui riferimenti a cosa accade in memoria, dato che solo così si potranno sfruttare appieno le potenzialità della programmazione OO.