Il vantaggio di utilizzare classi anziché solo subroutine è che le classi creano un livello di astrazione che consente di scrivere codice più pulito. Certo, se non hai mai usato le lezioni prima in VBA, c'è una curva di apprendimento, ma credo che valga sicuramente il tempo di capirlo.
Un'indicazione chiave che è necessario passare alle classi è se si aggiungono costantemente parametri alle proprie funzioni e subroutine. In questo caso, è quasi sempre meglio usare le classi.
Ho copiato una spiegazione di classi da one of my previous Stack Overflow answers:
Ecco un lungo esempio di come utilizzare una classe potrebbe aiutarvi. Sebbene questo esempio sia lungo, ti mostrerà come alcuni principi di programmazione orientata agli oggetti possono davvero aiutarti a ripulire il tuo codice.
Nell'editor VBA, andare a Insert > Class Module
. Nella finestra Proprietà (in basso a sinistra dello schermo per impostazione predefinita), modificare il nome del modulo in WorkLogItem
. Aggiungere il seguente codice alla classe:
Option Explicit
Private pTaskID As Long
Private pPersonName As String
Private pHoursWorked As Double
Public Property Get TaskID() As Long
TaskID = pTaskID
End Property
Public Property Let TaskID(lTaskID As Long)
pTaskID = lTaskID
End Property
Public Property Get PersonName() As String
PersonName = pPersonName
End Property
Public Property Let PersonName(lPersonName As String)
pPersonName = lPersonName
End Property
Public Property Get HoursWorked() As Double
HoursWorked = pHoursWorked
End Property
Public Property Let HoursWorked(lHoursWorked As Double)
pHoursWorked = lHoursWorked
End Property
Il codice di cui sopra ci darà un oggetto fortemente tipizzato che è specifico per i dati con i quali stiamo lavorando. Quando si utilizzano gli array a più dimensioni per archiviare i dati, il codice è simile al seguente: arr(1,1)
è l'ID, arr(1,2)
è il PersonName e arr(1,3)
è HoursWorked. Usando questa sintassi, è difficile sapere cosa sia cosa. Supponiamo che tu continui a caricare i tuoi oggetti in un array, ma invece usi lo WorkLogItem
che abbiamo creato sopra. Con questo nome, potresti ottenere arr(1).PersonName
per ottenere il nome della persona. Questo rende il tuo codice molto più facile da leggere.
Continuiamo a muoverci con questo esempio. Invece di archiviare gli oggetti nell'array, proveremo a utilizzare collection
.
Successivamente, aggiungere un nuovo modulo di classe e chiamarlo ProcessWorkLog
. Inserire il seguente codice in là:
Option Explicit
Private pWorkLogItems As Collection
Public Property Get WorkLogItems() As Collection
Set WorkLogItems = pWorkLogItems
End Property
Public Property Set WorkLogItems(lWorkLogItem As Collection)
Set pWorkLogItems = lWorkLogItem
End Property
Function GetHoursWorked(strPersonName As String) As Double
On Error GoTo Handle_Errors
Dim wli As WorkLogItem
Dim doubleTotal As Double
doubleTotal = 0
For Each wli In WorkLogItems
If strPersonName = wli.PersonName Then
doubleTotal = doubleTotal + wli.HoursWorked
End If
Next wli
Exit_Here:
GetHoursWorked = doubleTotal
Exit Function
Handle_Errors:
'You will probably want to catch the error that will '
'occur if WorkLogItems has not been set '
Resume Exit_Here
End Function
La classe di cui sopra sta per essere usato per "fare qualcosa" con un colleciton di WorkLogItem
. Inizialmente, l'abbiamo appena impostato per contare il numero totale di ore lavorate. Proviamo il codice che abbiamo scritto.Crea un nuovo modulo (non un modulo di classe questa volta, solo un modulo "normale"). Incollare il seguente codice nel modulo:
Option Explicit
Function PopulateArray() As Collection
Dim clnWlis As Collection
Dim wli As WorkLogItem
'Put some data in the collection'
Set clnWlis = New Collection
Set wli = New WorkLogItem
wli.TaskID = 1
wli.PersonName = "Fred"
wli.HoursWorked = 4.5
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 2
wli.PersonName = "Sally"
wli.HoursWorked = 3
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 3
wli.PersonName = "Fred"
wli.HoursWorked = 2.5
clnWlis.Add wli
Set PopulateArray = clnWlis
End Function
Sub TestGetHoursWorked()
Dim pwl As ProcessWorkLog
Dim arrWli() As WorkLogItem
Set pwl = New ProcessWorkLog
Set pwl.WorkLogItems = PopulateArray()
Debug.Print pwl.GetHoursWorked("Fred")
End Sub
Nel codice precedente, PopulateArray()
crea semplicemente un insieme di WorkLogItem
. Nel codice reale, è possibile creare classi per analizzare i fogli di Excel o gli oggetti dati per riempire una raccolta o un array.
Il codice TestGetHoursWorked()
mostra semplicemente come sono state utilizzate le classi. Si noti che ProcessWorkLog
viene creato come un oggetto. Dopo averlo istanziato, una raccolta di WorkLogItem
diventa parte dell'oggetto pwl
. Si nota questo nella riga Set pwl.WorkLogItems = PopulateArray()
. Successivamente, chiamiamo semplicemente la funzione che abbiamo scritto che agisce sulla collezione WorkLogItems
.
Perché è utile?
Supponiamo che i dati cambino e che tu voglia aggiungere un nuovo metodo. Supponiamo che il tuo WorkLogItem
includa ora un campo per HoursOnBreak
e tu voglia aggiungere un nuovo metodo per calcolarlo.
Tutto quello che dovete fare è aggiungere un alloggio ai WorkLogItem
in questo modo:
Private pHoursOnBreak As Double
Public Property Get HoursOnBreak() As Double
HoursOnBreak = pHoursOnBreak
End Property
Public Property Let HoursOnBreak(lHoursOnBreak As Double)
pHoursOnBreak = lHoursOnBreak
End Property
Naturalmente, è necessario modificare il metodo per la compilazione vostra collezione (il metodo di esempio che ho usato era PopulateArray()
, ma probabilmente dovresti avere una classe separata solo per questo). Poi basta aggiungere il nuovo metodo per la classe ProcessWorkLog
:
Function GetHoursOnBreak(strPersonName As String) As Double
'Code to get hours on break
End Function
Ora, se volessimo aggiornare il nostro metodo TestGetHoursWorked()
al risultato di GetHoursOnBreak
tornare, tutti avremmo dovuto fare come aggiungere la seguente riga:
Debug.Print pwl.GetHoursOnBreak("Fred")
Se passavi in una serie di valori che rappresentavano i tuoi dati, dovresti trovare ogni posizione nel codice in cui hai utilizzato gli array e quindi aggiornarli di conseguenza. Se invece usi le classi (e i loro oggetti istanziati), puoi molto più facilmente aggiornare il tuo codice per lavorare con le modifiche. Inoltre, quando consenti alla classe di essere consumata in più modi (forse una funzione ha bisogno solo di 4 delle proprietà degli oggetti mentre un'altra funzione ne avrà bisogno 6), possono comunque fare riferimento allo stesso oggetto. Questo ti impedisce di disporre di più array per diversi tipi di funzioni.
Per ulteriore lettura, vorrei altamente consiglia di ottenere una copia di VBA Developer's Handbook, 2nd edition. Il libro è pieno di ottimi esempi e best practice e tonnellate di codice di esempio. Se investi molto tempo in VBA per un progetto serio, vale la pena dedicare tempo a esaminare questo libro.
+1, GRANDE risposta. Chiaro, nitido e molto utile per tutti. –
+1 per il manuale dello sviluppatore VBA! –
Ancora utile 5 anni dopo, grazie Ben! +1 da me. – FreeMan