Capitoli di esempio

Transcript

Capitoli di esempio
Capitolo 14
Introduzione
ai moduli di classe
312
Proprietà, metodi
ed eventi
315
Creare una classe
317
Struttura
delle classi
324
Sviluppare
moduli di classe
Questo capitolo introduce il concetto delle classi. In questo
capitolo imparerai cosa sono le classi e gli oggetti, e il motivo
per cui i due termini non vanno confusi. Imparerai inoltre come
creare le classi in Microsoft Visual Basic for Applications (VBA)
e come definirne le proprietà, i metodi e gli eventi.
Che cos’è un oggetto?
Un oggetto è la rappresentazione logica di una cosa. La cosa può
essere un’entità fisica, come una persona, un fiore, una macchina o un luogo, oppure può essere un’entità logica, come un
rapporto, un ordine o una transazione. La cosa può anche rappresentare un entità del computer, come un pulsante, una cella, un foglio di lavoro o un modulo.
Che cos’è una classe?
Una classe è un modello dal quale si crea un oggetto. Questo
modello comprende sia variabili che codice, condensati in una
singola entità. Un oggetto rappresenta una singola istanza di una
classe, che può essere modificata dal tuo programma.
Sei un po’ confuso? Pensa alla classe come a un tipo di dati, come
Integer o String. Prima di poter usare un Integer o String, devi
dichiarare una variabile di quel tipo. Così come è possibile avere diverse variabili definite come Integer o String, è anche possibile avere diverse variabili definite come istanze di un’unica classe.
In Visual Basic for Applications, le classi sono implementate
attraverso i moduli di classe. Ciascun modulo di classe contiene esattamente una classe e comprende tutte le proprietà i
metodi e gli eventi associati con l’interfaccia della classe, oltre
a tutte le altre variabili locali, funzioni e subroutine necessarie
a far funzionare correttamente la classe.
311
Parte 4: VBA avanzato
Che cosa sono le proprietà?
Le proprietà sono attributi della cosa che un oggetto rappresenta. Per esempio, un fiore avrà attributi come il nome, il colore, le dimensioni, e così via. Gli attributi di una persona saranno per esempio
il nome, l’indirizzo, il numero del documento d’identità e la data di nascita.
Capitolo 14
Un oggetto può anche contenere riferimenti ad altri oggetti. Un ordine potrebbe avere un riferimento al
cliente, o un modulo potrebbe contenere un pulsante. Ai fini di questa trattazione, questi riferimenti ad
oggetti possono anche caratterizzati come proprietà. Un oggetto può anche rappresentare un gruppo di
cose simili. Per esempio, l’oggetto Impiegati potrebbe contenere un gruppo di singoli oggetti Impiegato.
suggerimento
Gli aggettivi descrivono i nomi
È possibile pensare agli oggetti come nomi e alle proprietà come aggettivi, per esempio il fiore rosso
o la persona alta due metri. Questo concetto non è perfetto, perché alcuni attributi sono piuttosto
specifici, ad esempio un camion con 60.500 km, ma quest’idea può essere utile nei primi tempi del
tuo lavoro con gli oggetti.
Che cosa sono i metodi?
I metodi sono azioni compiute dall’oggetto. Per esempio, l’oggetto di un rapporto può comprendere un metodo di stampa che invia il rapporto a una stampante. Un altro modo di immaginare i metodi
è pensare che i metodi descrivono le operazioni compiute con le informazioni contenute nelle proprietà dell’oggetto.
suggerimento
I verbi descrivono le azioni
Puoi caratterizzare i metodi come verbi che compiono un’operazione o un’attività con le proprietà
dell’oggetto.
Che cosa sono gli eventi?
Pur non essendo esattamente una parte del modello di programmazione degli oggetti, gli eventi sono
un utile strumento che permette a un oggetto di scambiare informazioni con il programma che ha
creato l’oggetto. In altri termini, un evento è una subroutine residente nel programma che ha creato l’oggetto, ed è chiamata dall’oggetto.
Un evento è una tecnica utile che elimina la necessità del programma di monitorare costantemente
le modifiche di un oggetto. In questo modo, l’oggetto chiama l’evento per informare il programma
di una modifica allo stato dell’oggetto.
Introduzione ai moduli di classe
I moduli di classe sono tra gli strumenti più importanti per il programmatore in VBA. Un modulo
di classe ti permette di creare degli oggetti e di modificarli, come se fossero oggetti già forniti con
312
Capitolo 14: Sviluppare moduli di classe
Microsoft Excel. E proprio come gli oggetti disponibili in Excel, un modulo di classe può avere proprietà, metodi ed eventi.
C’è una grande differenza tra una variabile semplice e una variabile oggetto. La variabile oggetto non
è che un puntatore all’interno della memoria. Dovrai creare esplicitamente un oggetto e salvare la
sua posizione nella variabile oggetto. Questo processo si chiama creare una nuova istanza di un oggetto o istanziare un oggetto.
Poiché gli oggetti sono diversi dalle variabili, Visual Basic for Applications utilizza una speciale istruzione chiamata istruzione Set.
L’istruzione Set ha due forme. Ecco la prima:
Set VariabileOggetto = New NomeClasse
In questa forma, l’istruzione Set crea un nuovo oggetto basato su NomeClasse. Ciò significa che Visual
Basic allocherà memoria per l’oggetto e salverà la posizione in memoria nella classe VariabileOggetto.
Set VariabileOggetto = EspressioneOggetto
Nella seconda forma, l’istruzione Set fa due cose: prima di tutto l’istruzione rilascia l’oggetto a cui
puntava, quindi salva un puntatore a un oggetto già esistente in VariabileOggetto.
Quando vengono davvero creati gli oggetti?
La parola chiave New in un’istruzione Dim, Public o Private non crea una nuova istanza di un oggetto. Invece, Visual Basic aggiunge del codice davanti a ogni riferimento all’oggetto per vedere
se è stata creata una nuova istanza della classe. Se non è stata creata una nuova istanza della classe, l’oggetto sarà creato automaticamente prima di essere utilizzato.
Nella maggior parte dei casi non c’è una grossa differenza nell’usare un’istruzione Dim o un’istruzione Set per creare una nuova istanza della classe. Tuttavia, usare l’istruzione Set New è leggermente più efficiente che usare l’istruzione Dim New, perché Visual Basic non genera il codice
supplementare per verificare che sia stata creata una nuova istanza della classe.
Usare un’istruzione Set New anziché Dim New permette anche di evitare alcuni problemi di debug.
Supponi di trovarti in una situazione in cui credi di aver creato una nuova istanza di una classe, ma
per qualche motivo non è stato creato l’oggetto. Usando Dim New, l’oggetto sarà creato automaticamente e il tuo programma potrebbe cercare di utilizzare l’oggetto aspettandosi che questo
contenga delle informazioni, ma non è così perché l’oggetto è stato appena creato.
Creare l’oggetto con Set New implica che l’oggetto non può essere creato al momento, e nel tuo
programma si verificherebbe un errore di run-time se cercasse di accedere a un oggetto che non è
ancora stato creato. L’errore di run-time, pur essendo fastidioso, ti indicherebbe che in qualche punto
del tuo codice c’è un problema. Altrimenti, potresti non accorgerti neppure della presenza di un bug.
313
Capitolo 14
Accedere agli oggetti
Parte 4: VBA avanzato
Dichiarare gli oggetti
Puoi dichiarare un oggetto usando un’istruzione Dim, Public o Private, in due forme diverse. Ecco
la prima:
Dim VariabileOggetto As NomeClasse
Capitolo 14
Questa istruzione riserva semplicemente lo spazio per VariabileOggetto, e la variabile ora ha un tipo
di NomeClasse
Dim VariabileOggetto As New NomeClasse
Questa seconda forma fa le stesse cose della prima, ma creerà automaticamente un nuovo oggetto
la prima volta che VariabileOggetto sarà referenziata.
Oggetti e Nothing
Visual Basic for Applications contiene un valore speciale chiamato Nothing. Questo valore può essere usato solo con gli oggetti. Nothing è il valore associato con una variabile oggetto che non punta
al momento a un’istanza di una classe. Una variabile oggetto dichiarata con un’istruzione Dim sarà
inizialmente impostata a Nothing.
È possibile determinare se è stata creata una nuova istanza di classe usando Is Nothing in un’istruzione If come questa:
If VariabileOggetto Is Nothing Then
attenzione
L’espressione VariabileOggetto Is Not Nothing, pur avendo senso in lingua inglese, non viene capita da Visual Basic for Applications. Se devi verificare che una variabile oggetto si riferisce a un’istanza di un oggetto, dovresti usare l’espressione Not VariabileOggetto Is Nothing. La verifica Is Nothing
dà come risultato un valore booleano e può essere usata ovunque si possa utilizzare un’espressione booleana.
La seguente istruzione può essere usata per distruggere un oggetto:
Set VariabileOggetto = Nothing
Quest’istruzione libererà il riferimento all’oggetto e imposterà la variabile oggetto al suo stato non
inizializzato. Assumendo che ci sia solo una variabile oggetto che punta all’oggetto, questa istruzione
distruggerà anche l’oggetto e libererà tutte le risorse associate a esso.
Tuttavia, se diverse variabili oggetto puntano a questo oggetto, occorre impostarle tutte a Nothing
prima che l’oggetto venga distrutto. Per esempio, nel seguente frammento di codice, l’oggetto creato dalla classe MiaClasse continua a esistere, anche se VariabileOggetto1 viene impostata a Nothing.
314
Capitolo 14: Sviluppare moduli di classe
Set VariabileOggetto1 = New MiaClasse
Set VariabileOggetto2 = VariabileOggetto1
Set VariabileOggetto1 = Nothing
È importante ricordare che un oggetto non è la stessa cosa di una variabile oggetto. Per esempio, il
seguente codice crea un oggetto con due variabili che puntano a esso:
Set OggettoA = New MiaClasse
Set OggettoB = OggettoA
La prima istruzione Set crea una nuova istanza di MiaClasse, mentre la seconda istruzione Set crea
semplicemente un secondo puntatore allo stesso oggetto creato dalla prima istruzione.
Ciò significa che le seguenti dichiarazioni faranno lo stesso, dal momento che sia OggettoA che
OggettoB puntano allo stesso oggetto:
OggettoA.Nome = "Rose"
OggettoB.Nome = "Rose"
Se questo non ti confonde troppo, eseguire la seguente istruzione non distruggerà l’oggetto:
Set OggettoA = Nothing
Poiché OggettoB punta ancora all’oggetto, questo rimarrà in memoria finché anche OggettoB sarà
impostato a Nothing.
Proprietà, metodi ed eventi
Esiste una serie di proprietà, metodi ed eventi associati a ogni oggetto, che servono per scambiare
informazioni tra l’oggetto e la routine che ha creato l’oggetto.
Proprietà, metodi ed eventi Public e Private
Le singole parti di una classe possono essere etichettate come Public o Private. Tutto ciò che è contrassegnato come Public è visibile a chiunque usi le classi, mentre ciò che è marcato come Private è
accessibile solo dal codice all’interno della classe.
suggerimento
Non affidarti alle impostazioni predefinite
Contrassegna sempre esplicitamente tutto ciò che è contenuto in una classe come Public o Private, in modo da non doverti preoccupare se l’impostazione predefinita fosse Public o Private.
315
Capitolo 14
Oggetti con più variabili oggetto
Parte 4: VBA avanzato
Proprietà
All’interno di una classe troverai molte cose diverse. Puoi definire delle variabili a livello di classe,
che sono accessibili da qualsiasi punto della classe. Se una variabile a livello di classe è contrassegnata
come Public, diventa disponibile a chiunque usi la classe, ed è quindi una proprietà della classe.
Capitolo 14
Oltre alle variabili a livello di classe, le proprietà potrebbero anche avere del codice a loro associato.
Ogni proprietà in cui vuoi usare del codice è organizzata in due routine, che restituiscono il valore
al programma chiamante o modificano il valore nella classe. La routine Get restituisce il valore al
chiamante, mentre le routine Let o Set permettono al chiamante di assegnare un valore alla proprietà.
Ricorda che puoi definire una proprietà soltanto con una routine Get oppure con una routine Let o
Set. Se utilizzi solo una routine Get, la proprietà diventa di sola lettura e il suo valore non può essere
modificato dal programma usando l’oggetto. Similmente, se inserisci solo una routine Let o Set, la
proprietà diventa di sola scrittura, e il suo valore non può essere visto dal programma chiamante.
Metodi
Insieme alle variabili di livello classe e alle routine di proprietà, una classe può anche contenere una
serie di subroutine e funzioni regolari. Se una funzione o una subroutine è contrassegnata come
Public, viene chiamata metodo. I metodi possono essere invocati dal codice che risiede all’interno o
al di fuori della classe.
Eventi
Gli eventi sono subroutine che esistono al di fuori del codice associato con la classe, che possono essere
chiamate da istruzioni all’interno della classe. Gli eventi forniscono alla classe un modo per interrompere il programma che ha creato un’istanza dell’oggetto dalla classe, permettendo quindi al
programma di eseguire le proprie operazioni in risposta a una situazione incontrata dall’oggetto.
Ricorda che il codice associato a un evento in realtà risiede al di fuori della classe. Le uniche informazioni memorizzate all’interno della classe sono la definizione dell’evento con i parametri che
saranno passati al programma esterno.
nota Le classi che contengono eventi richiedono che nella dichiarazione dell’oggetto ci sia la parola chiave
WithEvents. Se nella dichiarazione non c’è questa parola chiave, gli eventuali eventi che si verificano saranno ignorati dal programma esterno.
Tutte queste proprietà pubbliche, metodi ed eventi di una classe formano l’interfaccia dell’oggetto.
L’interfaccia isola il codice all’interno della classe dal codice che utilizza l’oggetto creato da questa classe.
Quest’isolamento è molto utile per vari motivi. Innanzitutto, ti permette di verificare le classi indipendentemente dal resto dell’applicazione. Quando ritieni che la classe sia stabile, potrai trattarla come
una scatola nera che funziona. In secondo luogo, facilita il lavoro di più persone su un’unica applicazione. Una persona può lavorare alla classe mentre altri lavorano al codice che utilizza la classe. Inoltre, è possibile modificare il codice all’interno della classe senza necessariamente avere un impatto sulle
applicazioni che utilizzano la classe. In questo modo si possono implementare nuovi algoritmi o aggiungere nuove caratteristiche alla classe senza cambiare i programmi che utilizzano la classe.
316
Capitolo 14: Sviluppare moduli di classe
Creare una classe
Il modulo di classe contiene tutte le proprietà, metodi ed eventi associati con l’interfaccia della classe,
insieme a tutte le variabili locali, le funzioni e le subroutine usate dalla classe.
Puoi aggiungere un modulo di classe al tuo programma in VBA scegliendo Inserisci, Modulo di classe
dal menu principale di Visual Basic. Il nome iniziale della classe è formato aggiungendo un numero unico alla parola Classe. Così, la prima classe che creerai sarà Classe1, e la seconda sarà Classe2.
Dal momento che un nome come Classe1 non è molto descrittivo, dovresti sempre dare alla classe
un nome più significativo. Per modificare il nome di una classe, seleziona la classe nella finestra
Gestione progetti, quindi vai alla finestra Proprietà e modifica la proprietà Name associata a questa
classe (vedi figura 14-1).
Figura 14-1. Usa la finestra Proprietà per modificare la proprietà Name associata alla classe.
Definire proprietà semplici
Ci sono due diversi tipi di proprietà: variabili di livello classe pubbliche e routine di proprietà. Le
variabili di livello classe devono essere definite prima di qualsiasi subroutine, funzione o proprietà.
In termini pratici, ciò significa che tutte le variabili di livello classe dovrebbero trovarsi all’inizio del
modulo di classe.
317
Capitolo 14
Creare un modulo di classe
Parte 4: VBA avanzato
Per esempio, la seguente riga definisce una proprietà semplice:
Public CodiceArticolo As Long
attenzione
Capitolo 14
Le proprietà semplici non possono essere usate per restituire una matrice, una stringa a lunghezza fissa, una costante o una struttura complessa creata con un istruzione Type. Se ti occorre una proprietà
che restituisca una di queste cose, crea la variabile di livello classe privata adeguata e quindi crea una
routine Property che esegua la stessa azione. Per esempio, puoi creare una routine di proprietà che accetti
una serie di parametri che permettano alla routine di sembrare una matrice. Similmente, puoi creare una
routine di proprietà che accetti e restituisca stringhe a lunghezza fissa o strutture complesse.
Definire routine di proprietà
Ci sono tre diversi tipi di routine di proprietà: Get, Set e Let. La routine Property Get restituisce sempre
un valore. Ecco un semplice esempio che si riferisce a una variabile di livello classe privata che è stata
chiamata IlNomeDelProdotto.
Public Property Get NomeProdotto As String
NomeProdotto = IlNomeDelProdotto
End Property
Le routine Property Let e Property Set sono chiamate per salvare un valore nella proprietà. L’istruzione Property Let è utilizzata quando la proprietà è una normale variabile, mentre l’istruzione
Property Set è usata quando la proprietà è un oggetto.
La routine Property Let corrispondente alla proprietà NomeProdotto sarebbe simile a questa:
Public Property Let NomeProdotto(valore As String)
IlNomeDelProdotto = valore
End Property
nota L’unica differenza tra un’istruzione Property Set e un’istruzione Property Let è che Property Set si utilizza
quando si lavora con gli oggetti, mentre normalmente si assegnerebbero i valori usando l’istruzione
Set. Similmente, si utilizza Property Let quando si restituisce un qualsiasi altro valore. Le routine di
proprietà possono anche avere uno o più parametri. Di solito si utilizzano parametri con una routine
di proprietà per simulare una matrice. Per esempio, il seguente frammento di codice dichiara una
variabile di livello classe privata chiamata Nomi, che è una matrice di 100 String. Il frammento di codice
comprende anche due routine di proprietà che fanno sembrare la proprietà una matrice.
318
Capitolo 14: Sviluppare moduli di classe
Private Nomi (99) As String
Public Property Get NomeMatrice(indice As Long) As String
NomeMatrice = Nomi(indice)
Capitolo 14
End Property
Public Property Let NomeMatrice(indice As Long, valore as String)
Nomi = valore
End Property
nota Puoi specificare quanti parametri vuoi per le routine di proprietà. Tuttavia, essi devono essere identici
tra le routine Get e Let/Set, eccezion fatta per l’ultimo parametro della routine Let/Set, che contiene il valore della proprietà.
Una persona che utilizza la classe può accedere alla proprietà così:
Oggetto.NomeMatrice (10) = "Elemento 10 nella matrice"
Oppure così:
Variabile = Oggetto.NomeMatrice (10)
suggerimento
Routine di proprietà e parametri
Pur essendo possibile specificare un elenco di parametri per una routine di proprietà, dovresti limitare l’uso dei parametri in una routine di proprietà a quei parametri che rendono la routine di proprietà somigliante a una matrice. Se ti occorre utilizzare parametri piuttosto che subscript, dovresti
prendere in considerazione di creare uno o più metodi con i parametri che ti servono.
319
Parte 4: VBA avanzato
Usare le istruzioni di proprietà
con i tipi definiti dall’utente
Se hai definito un insieme di routine di proprietà per manipolare una struttura complessa creata con
un’istruzione Type, potresti riscontrare dei problemi quando cerchi di assegnare un valore direttamente a uno degli elementi nella struttura in un’unica istruzione. Supponi che la tua classe contenga le seguenti istruzioni:
Capitolo 14
Public Type CoordinateMappaType
Latitudine As Single
Longitudine As Single
End Type
Private MiaCoordinateMappa As CoordinateMappaType
Public Property Get CoordinateMappa As CoordinateMappaType
CoordinateMappa = MiaCoordinateMappa
End Property
Public Property Let CoordinateMappa (valore as CoordinateMappaType)
CoordinateMappa = valore
End Property
Ora, assumendo che tu abbia istanziato la classe come MicrosoftWay, puoi fare riferimento al valore Latitudine in questo modo:
TempLatitudine = MicrosoftWay.CoordinateMappa.Latitudine
Poiché questa funziona, potresti essere tentato di usare le seguenti istruzioni:
MicrosoftWay.Coordinate.Latitudine = 47.63
MicrosoftWay.Coordinate.Longitudine = 122.13
Tuttavia, se le usi, scoprirai che MicrosoftWay.CoordinateMappa.Latitudine è zero!
Sebbene questo possa sembrare un bug di Visual Basic, in realtà non lo è. Visual Basic funziona
correttamente. Quando fai riferimento all’elemento Latitudine nella prima istruzione, Visual Basic
crea una variabile temporanea CoordinateMappaType e imposta il valore Latitudine a 47.63. Poiché la variabile temporanea è riempita con gli zeri quando viene allocata e non c’è un valore assegnato esplicitamente a Longitudine, questo contiene un valore di zero. Così, quando viene chiamata
la routine Let Coordinate, con la variabile temporanea creata da Visual Basic, l’elemento Latitudine sarà impostato a 47.63 e l’elemento Longitudine sarà impostato a zero.
320
Capitolo 14: Sviluppare moduli di classe
Usare le istruzioni di proprietà con i tipi definiti dall’utente (continua)
Ci sono un paio di modi per evitare questo problema. Il primo modo, e probabilmente il migliore,
è creare una classe anziché usare un’istruzione Type. Tuttavia, se desideri proprio usare un’istruzione Type, dovresti creare una tua variabile temporanea, assegnare i valori alla struttura e assegnare la struttura alla proprietà in questo modo:
Dim TempVar As CoordinateMappaType
TempVar.Latitudine = 47.63
TempVar.Longitudine = 122.13
MicrosoftWay.CoordinateMappa = TempVar
Definire metodi
I metodi sono semplicemente funzioni e subroutine pubbliche. Essi sono liberi di accettare qualsiasi insieme di parametri e restituire qualsiasi tipo di valore. Possono inoltre accedere a qualunque
variabile di livello classe, sia pubblica che privata, e a qualunque routine di proprietà. Per esempio,
supponi che la classe contenga informazioni su un prodotto particolare di The Garden Company.
Potresti creare una funzione che calcoli il prezzo scontato in questo modo:
Public Function PrezzoScontato (Sconto As Currency) As Currency
If Sconto >= 0 and Sconto < 1.0 Then
PrezzoScontato = PrezzoListino * (1 - Sconto)
Else
PrezzoScontato = PrezzoListino
End If
End Function
Questa routine verifica che il parametro di input sia valido controllando che sai un valore compreso tra 0 e 1 e calcoli di conseguenza il prezzo scontato. Se il valore scontato non è valido, viene restituito il prezzo di listino dell’articolo.
suggerimento
Risparmiare cicli
Potendo scegliere tra usare una routine di proprietà o una variabile di livello classe privata, opta
per la variabile di livello classe privata. In questo modo, evitando i maggiori cicli del processore e
la memoria richiesta dalla routine di proprietà, l’applicazione sarà più veloce.
321
Capitolo 14
La stessa situazione si verifica quando esegui la seconda istruzione. Poiché non è stato assegnato
un valore a Latitudine nella variabile temporanea, il valore precedente di 47.63 sarà sovrascritto
da zero, e questo annulla la modifica fatta nella prima istruzione.
Parte 4: VBA avanzato
Definire eventi
Gli eventi possono essere molto utili in una classe, ma non puoi dare per scontato che tutti coloro
che usano la tua classe useranno gli eventi. Perciò, se decidi di usare gli eventi nella tua classe, devi
assicurarti che la classe continui a funzionare anche se l’utente non risponde a nessuno degli eventi.
Capitolo 14
Per definire un evento si usa l’istruzione Event. Agli scopi pratici, è in effetti una istruzione di
subroutine meno il codice. La definizione è necessaria perché identifica i parametri che saranno
passati all’evento. La definizione di evento è usata dal compilatore Visual Basic per garantire che il
numero e il tipo dei parametri e corrisponda alla definizione.
nota Sebbene sia possibile specificare quasi tutti i tipi di parametro che si possono usare in una subroutine,
gli eventi non possono avere argomenti denominati, parametri facoltativi o argomenti ParamArray.
Un esempio di definizione di esempio può essere come questo:
Event ErroreSconto (value As Currency, Msg As String)
All’interno della classe, puoi usare un’istruzione RaiseEvent per generare un evento nel programma
utente. L’istruzione RaiseEvent è seguita dal nome dell’evento e da un elenco di valori che saranno
passati al programma utente. Per esempio, questa istruzione ripassa due valori al programma chiamante.
RaiseEvent ErroreSconto(Sconto, "Cifra scontata non valida. ")
Per usare gli eventi in un’applicazione, deve essere inserita la parola chiave WithEvents quando si
definisce l’oggetto. Senza la parola chiave WithEvents, tutti gli eventi saranno ignorati. La seguente
istruzione mostra come dovresti dichiarare un oggetto con eventi:
Dim WithEvents Oggetto As GardenCompany
Definire variabili, subroutine e funzioni private
Sebbene non sia necessario contrassegnare le subroutine o le funzioni come Private in una classe,
nota che senza la parola chiave Private, qualsiasi subroutine o funzione sarà Public per impostazione predefinita. In molte situazioni, questo potrebbe non essere un grosso problema, specialmente
se sei l’unico a utilizzare la classe. Tuttavia, se intendi condividere la tua classe con altri, potresti
scoprire che questi si affidano a una routine in cui hai accidentalmente omesso la parola chiave
Private, e non potresti cambiare la definizione della routine senza avere un impatto su tutti i programmi che la usano.
322
Capitolo 14: Sviluppare moduli di classe
Eventi speciali per le classi
VBA definisce due eventi speciali per tutte le classi: l’evento Initialize e l’evento Terminate.
Questo evento è utile per inizializzare le variabili di livello classe ed eseguire tutte le istruzioni Set
New necessarie a creare tutti gli oggetti richiesti da quest’oggetto.
Set VariabileOggetto = New Class
L’evento Class_Terminate contiene un codice che verrà avviato appena prima che un oggetto venga
distrutto. Questo evento è un luogo ideale per distruggere oggetti che sono locali alla classe, impostandoli a Nothing con un codice simile a questo:
Set VariabileOggetto = Nothing
nota Gli eventi Class_Initialize e Class_Terminate sono attivati solo quando l’oggetto vero e proprio è
creato o distrutto. La semplice impostazione di una variabile oggetto a un’altra non avvierà l’evento
Class_Initialize. Se due o più variabili puntano allo stesso oggetto, la semplice impostazione di una
variabile oggetto a Nothing non avvierà l’evento Class_Terminate.
Risolvere i riferimenti
A volte ti troverai in una situazione in cui avrai una variabile locale e una variabile a livello di classe
con lo stesso nome. Questo spesso capita quando vuoi dare a un parametro in un metodo lo stesso
nome di una proprietà. Per differenziare una variabile di livello classe da una variabile o un parametro locale, puoi aggiungere il prefisso Me. Alla variabile di livello classe, come nel seguente esempio:
If Me.Nome <> Nome Then
In questa istruzione, la variabile Me.Nome si riferisce a una variabile a livello di classe, mentre la
variabile Nome non qualificata si riferisce a una variabile o a un parametro locale.
suggerimento
Identificare ciò che appartiene a Me
La parola chiave Me può essere usata anche per qualificare un qualsiasi elemento pubblico o privato di una classe contenuto nel codice all’interno della classe, tra cui variabili di livello classe,
subroutine, funzioni e routine di proprietà.
323
Capitolo 14
L’evento Class_Initialize contiene un codice che sarà eseguito quando verrà creato un oggetto basato su questa classe.
Parte 4: VBA avanzato
Struttura delle classi
Ora che sai che cos’è una classe e come è possibile costruirne una, vale la pena di esporre brevemente
alcuni suggerimenti pratici per la costruzione delle classi.
Una classe semplice
Capitolo 14
È abbastanza ragionevole creare una classe che contenga soltanto proprietà e nessun metodo (vedi
figura 14-2).
Figura 14-2. Puoi costruire facilmente una classe semplice nell’editor di Visual Basic.
Puoi creare questa classe attenendoti a questi passaggi:
1 Seleziona Inserisci, Modulo di classe dal menu principale di VBA.
2 Seleziona la nuova classe nella finestra Gestione progetti e modifica la proprietà Name nella
finestra Proprietà in Pianta.
3 Inserisci le seguenti istruzioni:
Public NomeComune As String
Public NomeScientifico As String
Public Descrizione As String
Public PrezzoDettaglio As Currency
Public PrezzoIngrosso As Currency
Public CodiceProdotto As Long
324
Capitolo 14: Sviluppare moduli di classe
Estendere una classe semplice
Uno dei vantaggi dell’usare una classe per contenere dei dati collegati tra loro è che puoi estendere
facilmente la classe usando molte tecniche diverse. Per esempio, puoi aggiungere un sinonimo per
una proprietà esistente con un paio di routine di proprietà in questo modo:
Public Property Get Nome() As String
Capitolo 14
Nome = NomeComune
End Property
Public Property Let Nome(valore As String)
NomeComune = valore
End Property
Queste routine sono usate per restituire e modificare una variabile di livello classe pubblica, permettendo così all’utente di manipolare lo stesso valore usando due nomi diversi.
Un’altra utile tecnica è aggiungere un metodo che ti permetta di inizializzare tutte le proprietà della classe con un’unica chiamata. Nota che la seguente routine si avvale della parola chiave Me in modo
che chiunque utilizzi questo metodo sappia quali parametri hanno effetto su quale proprietà.
Public Sub Inizializza(NomeComune As String, _
NomeScientifico As String, _
Descrizione As String, _
PrezzoDettaglio As Currency, _
PrezzoIngrosso As Currency, _
CodiceProdotto As Long)
Me.NomeComune = Nome
Me.NomeScientifico = NomeScientifico
Me.Descrizione = Descrizione
Me.PrezzoDettaglio = PrezzoDettaglio
Me.PrezzoIngrosso = PrezzoIngrosso
Me.CodiceProdotto = CodiceProdotto
End Sub
Una classe Collection
Spesso è utile creare una classe di raccolta per racchiudere un gruppo di oggetti. Questa operazione è notevolmente semplificata utilizzando l’oggetto Collection di Visual Basic per immagazzinare i
dati. Il seguente codice dichiara una variabile oggetto Collection che è locale nella classe. La prima
volta che la classe è istanziata viene creato l’oggetto Collection, e quando l’oggetto viene distrutto si
distrugge anche l’oggetto Collection.
325
Parte 4: VBA avanzato
Private MyPiante As Collection
Private Sub Class_Initialize()
Set MyPiante = New Collection
End Sub
Capitolo 14
Private Sub Class_Terminate()
Set MyPiante = Nothing
End Sub
Un oggetto viene aggiunto alla classe di raccolta usando il seguente codice. Il codice assume che l’oggetto che si aggiunge abbia una proprietà Nome di tipo String. La routine inizia usando l’istruzione
On Error Resume Next per disattivare l’intercettazione degli errori. Tutti gli eventuali errori forzeranno Visual Basic a eseguire l’istruzione seguente. Per scoprire se si è verificato un errore, si utilizza l’oggetto Err.
Public Sub Aggiungi(Elemento As Pianta)
Dim i As Long
Dim s As String
On Error Resume Next
i = 0
s = Elemento.Nome
MyPiante.Aggiungi Elemento, s
Do While Err.Number <> 0
i = i + 1
Elemento.Nome = s & "(" & FormatNumber(i, 0) & ")"
Err.Clear
MyPiante.Add Elemento, Elemento.Nome
Loop
End Sub
Il contatore i è inizialmente impostato a zero, e il nome del nuovo oggetto è salvato nella variabile
temporanea s. Quindi si usa il metodo Add dell’oggetto Collection per aggiungere il nuovo oggetto
all’oggetto Collection.
326
Capitolo 14: Sviluppare moduli di classe
Se si verifica un errore nel metodo Add, il contatore i è incrementato. Un nuovo Nome per l’oggetto
viene costruito usando il nome originale seguito da una parentesi aperta, il numero del contatore i
e una parentesi chiusa. Quindi la routine tenta ancora di aggiungere un nuovo oggetto alla raccolta.
Se il metodo Add fallisce di nuovo, il ciclo si ripete finché il nome dell’oggetto è unico.
Capitolo 14
Un elemento viene rimosso dalla raccolta chiamando il metodo Remove e specificando la posizione
relativa dell’oggetto o il valore della proprietà Name. In qualsiasi caso, il metodo Remove dell’oggetto
Collection è usato per rimuovere l’elemento dalla raccolta che sta alla base.
Public Sub Rimuovi(chiave As Variant)
MyPiante.Rimuovi chiave
End Sub
Allo stesso modo, il metodo Conta restituisce il numero di elementi della raccolta chiamando il
metodo Conta sottostante associato all’oggetto Collection.
Public Function Conta() As Long
Conta = MyPiante.Conta
End Function
Il metodo Cancella è utile se vuoi cancellare tutti gli oggetti della raccolta. Questa routine distrugge
solamente l’oggetto Collection alla base e quindi crea una nuova istanza dell’oggetto Collection.
Public Sub Cancella()
Set MyPiante = Nothing
Set MyPiante = New Collection
End Sub
Il metodo Item restituisce un singolo elemento della raccolta. Come nei metodi Remove e Count,
quest’elemento chiama semplicemente il metodo Item dell’oggetto Collection.
Public Function Elemento(chiave As Variant) As Pianta
Set Elemento = MyPiante.Elemento(chiave)
End Function
La seguente routine è una macro che si reitera in tutta la classe di raccolta che è appena stata creata.
La macro inizia creando un nuovo oggetto Piante chiamato MyPiante, che contiene una raccolta di
oggetti Pianta. Quindi il codice chiama il metodo AggiungiDati, che semplicemente aggiunge alcuni oggetti di esempio alla raccolta.
327
Parte 4: VBA avanzato
Sub Test()
Dim MyPiante As Piante
Dim p As Pianta
Dim i As Long
Set MyPiante = New Piante
Capitolo 14
MyPiante.AggiungiDati
For i = 1 To MyPiante.Conta
Set p = MyPiante.Elemento(i)
MsgBox p.Nome
Next i
Set p = Nothing
Set MyPiante = Nothing
End Sub
Successivamente utilizza un ciclo For Next per reiterarsi in tutti gli elementi della raccolta. La variabile oggetto p è impostata all’elemento corrente della raccolta, e la proprietà Nome è visualizzata in
una finestra di messaggio.
Nota che il primo elemento della raccolta comincia con 1, e il numero di elementi della raccolta è
recuperato dalla proprietà Conta della raccolta.
Da dove prendo i miei dati?
Le classi sono un modo ideale per raccogliere dei dati da un’origine esterna. Raccogliendo i dati in
una classe di raccolta Collection, puoi consentire al tuo programma di accedere ai dati indipendentemente dal modo in cui i dati sono fisicamente memorizzati.
In questo modo, se modifichi il tipo di memorizzazione dei dati, non dovrai cambiare il modo per
accedere ai dati. Fornendo un metodo chiamato CaricaDati, chiunque utilizzi la classe può caricare i dati dall’origine. Poi, se sposterai i dati da un foglio di lavoro a un database di Access, cambierà soltanto il metodo di caricamento. Il codice che accede alla classe Collection non cambierà, a meno
che non modifichi i parametri dal metodo CaricaDati.
Similmente, puoi fornire un metodo standard chiamato SalvaDati, che aggiornerebbe i dati ovunque fossero memorizzati. Con un po’ di lavoro potresti addirittura rendere il metodo abbastanza
intelligente da aggiornare solo gli oggetti che sono già stati modificati, anziché aggiornare tutti i
dati compresi quelli non aggiornati dall’utente.
328
Capitolo 14: Sviluppare moduli di classe
Una classe con regole di convalida
È anche possibile estendere una classe aggiungendo alcune regole di convalida di base. Per esempio,
il seguente metodo convalida le informazioni dell’oggetto Pianta. Questo codice semplicemente
controlla ogni proprietà nella classe con condizioni potenziali di errore e restituisce True se non trova
errori e False se ne trova.
Capitolo 14
Public Function Valido() As Boolean
If Len(Nome) = 0 Then
Valido = False
ElseIf Len(NomeScientifico) = 0 Then
Valido = False
ElseIf CostoIngrosso < 0 Then
Valido = False
ElseIf PrezzoDettaglio < CostoIngrosso Then
Valido = False
ElseIf CodiceProdotto < 0 Then
Valido = False
Else
Valido = True
End If
End Function
La procedura Valido potrebbe essere modificata per restituire un messaggio di errore nel testo oppure addirittura una matrice String contenente un elenco di errori trovati nei dati.
Un altro modo per trovare gli errori è usare le routine di proprietà. Per esempio, potresti creare una
routine Property Let come questa.
Public Property Let PrezzoDettaglio(valore As Currency)
If valore > CostoIngrosso Then
MyPrezzoDettaglio = valore
329
Parte 4: VBA avanzato
Else
RaiseEvent ErrorePianta(1, _
"Prezzo al dettaglio minore del costo all’ingrosso.")
End If
End Property
Capitolo 14
La classe comprende una variabile a livello di classe privata chiamata MyPrezzoDettaglio che contiene
il valore della proprietà PrezzoDettaglio. Se il nuovo valore di PrezzoDettaglio è maggiore di
CostoIngrosso, il nuovo prezzo al dettaglio sarà salvato nella variabile MyPrezzoDettaglio.
Tuttavia, se qualcuno tenta di impostare il prezzo al dettaglio più basso del costo all’ingrosso, l’evento
ErrorePianta si attiverà, passando i dettagli dell’errore al programma che contiene l’oggetto.
In questo capitolo hai imparato le differenze tra una classe e un oggetto. Inoltre, hai imparato come
creare le tue classi personalizzate e come definire le proprietà, le routine di proprietà, i metodi e gli
eventi.
Sono stati discussi alcuni suggerimenti di progettazione per riconoscere oggetti, proprietà e metodi.
Infine, hai imparato come progettare diversi tipi di classi, tra cui la classe semplice e la classe di raccolta Collection, e come estendere le classi, inizializzare le classi e implementare regole di convalida.
330