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