Quando utilizzare una class in VBA?

Quando è opportuno utilizzare una class in Visual Basic for Applications (VBA)?

Suppongo che lo sviluppo accelerato e la riduzione dei bug introduttivi sia un vantaggio comune per la maggior parte delle lingue che supportano OOP. Ma con VBA esiste un criterio specifico?

Dipende da chi svilupperà e manterrà il codice. Tipici scrittori di macro “Power User” che hackerano piccole app ad hoc potrebbero essere confusi usando le classi. Ma per uno sviluppo serio, le ragioni per utilizzare le lezioni sono le stesse di altre lingue. Hai le stesse restrizioni di VB6 – nessuna ereditarietà – ma puoi avere il polimorfismo usando le interfacce.

Un buon uso delle classi è rappresentare quadro e collezioni di entity framework. Ad esempio, vedo spesso il codice VBA che copia un intervallo di Excel in un array bidimensionale, quindi manipola l’array bidimensionale con un codice come:

Total = 0 For i = 0 To NumRows-1 Total = Total + (OrderArray(i,1) * OrderArray(i,3)) Next i 

È più leggibile copiare l’intervallo in una raccolta di oggetti con proprietà con nome appropriato, ad esempio:

 Total = 0 For Each objOrder in colOrders Total = Total + objOrder.Quantity * objOrder.Price Next i 

Un altro esempio è utilizzare le classi per implementare il modello di progettazione RAII (google per esso). Ad esempio, una cosa che potrei dover fare è di rimuovere la protezione di un foglio di lavoro, fare alcune manipolazioni, quindi proteggerlo di nuovo. L’utilizzo di una class garantisce che il foglio di lavoro verrà sempre protetto nuovamente anche se si verifica un errore nel codice:

 --- WorksheetProtector class module --- Private m_objWorksheet As Worksheet Private m_sPassword As String Public Sub Unprotect(Worksheet As Worksheet, Password As String) ' Nothing to do if we didn't define a password for the worksheet If Len(Password) = 0 Then Exit Sub ' If the worksheet is already unprotected, nothing to do If Not Worksheet.ProtectContents Then Exit Sub ' Unprotect the worksheet Worksheet.Unprotect Password ' Remember the worksheet and password so we can protect again Set m_objWorksheet = Worksheet m_sPassword = Password End Sub Public Sub Protect() ' Protects the worksheet with the same password used to unprotect it If m_objWorksheet Is Nothing Then Exit Sub If Len(m_sPassword) = 0 Then Exit Sub ' If the worksheet is already protected, nothing to do If m_objWorksheet.ProtectContents Then Exit Sub m_objWorksheet.Protect m_sPassword Set m_objWorksheet = Nothing m_sPassword = "" End Sub Private Sub Class_Terminate() ' Reprotect the worksheet when this object goes out of scope On Error Resume Next Protect End Sub 

È quindi ansible utilizzare questo per semplificare il codice:

 Public Sub DoSomething() Dim objWorksheetProtector as WorksheetProtector Set objWorksheetProtector = New WorksheetProtector objWorksheetProtector.Unprotect myWorksheet, myPassword ... manipulate myWorksheet - may raise an error End Sub 

Quando questo sub è terminato, objWorksheetProtector esce dal campo di applicazione e il foglio di lavoro viene nuovamente protetto.

Penso che i criteri siano gli stessi di altre lingue

Se hai bisogno di bind insieme diversi pezzi di dati e alcuni metodi e anche di gestire specificamente cosa succede quando l’object viene creato / terminato, le classi sono ideali

dì se hai alcune procedure che si triggersno quando apri un modulo e una di queste richiede molto tempo, potresti decidere di dedicare il tempo a ogni fase ……

È ansible creare una class cronometro con metodi per le funzioni ovvie per l’avvio e l’arresto, è quindi ansible aggiungere una funzione per recuperare il tempo finora e riportarlo in un file di testo, utilizzando un argomento che rappresenta il nome del processo in fase di cronometraggio. Potresti scrivere la logica per registrare solo le prestazioni più lente da investigare.

È quindi ansible aggiungere un object barra di avanzamento con i metodi per aprirlo e chiuderlo e visualizzare i nomi dell’azione corrente, oltre a tempi in ms e tempo rimanente probabile in base ai report archiviati precedenti ecc.

Un altro esempio potrebbe essere se non ti piace la spazzatura del gruppo di utenti di Access, puoi creare la tua class utente con i metodi per accedere e uscire e funzionalità per il controllo / controllo / controllo di accesso degli utenti a livello di gruppo certe azioni / errori di tracciamento ecc.

Ovviamente lo si può fare usando un insieme di metodi non correlati e un sacco di passaggi variabili, ma avere tutto incapsulato in una class mi sembra migliore.

Prima o poi ti avvicini ai limiti di VBA, ma è un linguaggio piuttosto potente e se la tua azienda ti lega a questo, puoi davvero ricavarne soluzioni valide e complesse.

Le classi sono estremamente utili quando si gestiscono le funzioni API più complesse e in particolare quando richiedono una struttura dati.

Ad esempio, le funzioni GetOpenFileName () e GetSaveFileName () accettano una struttura OPENFILENAME con molti membri. potresti non aver bisogno di approfittare di tutti loro, ma sono lì e dovrebbero essere inizializzati.

Mi piace racchiudere la struttura (UDT) e le dichiarazioni delle funzioni API in una class CfileDialog. L’evento Class_Initialize imposta i valori predefiniti dei membri della struttura, in modo tale che quando utilizzo la class, ho solo bisogno di impostare i membri che voglio modificare (attraverso le procedure di proprietà). Le costanti flag sono implementate come Enum. Quindi, ad esempio, per scegliere un foglio di calcolo da aprire, il mio codice potrebbe assomigliare a questo:

 Dim strFileName As String Dim dlgXLS As New CFileDialog With dlgXLS .Title = "Choose a Spreadsheet" .Filter = "Excel (*.xls)|*.xls|All Files (*.*)|*.*" .Flags = ofnFileMustExist OR ofnExplorer If OpenFileDialog() Then strFileName = .FileName End If End With Set dlgXLS = Nothing 

La class imposta la directory predefinita su Documenti, anche se volessi potrei cambiarla con la proprietà InitDir.

Questo è solo un esempio di come una class può essere estremamente utile in un’applicazione VBA.

Non direi che esiste un criterio specifico, ma non ho mai trovato un posto utile per utilizzare le classi nel codice VBA. Nella mia mente è così legato ai modelli esistenti attorno alle app di Office che aggiungendo ulteriori astrazioni al di fuori di quel modello di object confonde semplicemente le cose.

Questo non vuol dire che non si possa trovare un posto utile per una class in VBA, o fare cose perfettamente utili usando una class, solo che non le ho mai trovate utili in quell’ambiente.

È inoltre ansible riutilizzare il codice VBA senza utilizzare le classi effettive. Ad esempio, se hai un VBACode chiamato. È ansible accedere a qualsiasi funzione o sub in qualsiasi modulo con la seguente syntax:

 VBCode.mysub(param1, param2) 

Se crei un riferimento a un modello / documento (come faresti con una dll), puoi fare riferimento al codice di altri progetti allo stesso modo.

Lo sviluppo di software, anche con Microsoft Access, utilizzando la programmazione orientata agli oggetti è generalmente una buona pratica. Consentirà la scalabilità in futuro consentendo agli oggetti di essere accoppiati liberamente, insieme a una serie di vantaggi. Ciò significa fondamentalmente che gli oggetti nel tuo sistema saranno meno dipendenti l’uno dall’altro, quindi il refactoring diventa molto più semplice. È ansible ottenere questo è l’accesso utilizzando i moduli di class. Lo svantaggio è che non è ansible eseguire l’ereditarietà di class o il polimorfismo in VBA. Alla fine, non esiste una regola ferrea sull’uso delle classi, solo le migliori pratiche. Ma tieni presente che man mano che la tua applicazione cresce, tanto più facile è mantenere le classi.

Per la ricorsione dei dati (ovvero la gestione delle BOM), una class personalizzata è estremamente utile e a volte penso sia indispensabile. È ansible creare una funzione ricorsiva senza un modulo di class, ma molti problemi relativi ai dati non possono essere risolti in modo efficace.

(Non so perché le persone non siano fuori dalla distribuzione di serie di librerie BOM per VBA. Forse gli strumenti XML hanno fatto la differenza).

Istanze di moduli multiple è l’applicazione comune di una class (molti problemi di automazione sono altrimenti irrisolvibili), presumo che la domanda riguardi le classi personalizzate .

Uso le classi quando devo fare qualcosa e una class lo farà meglio 🙂 Ad esempio, se devi rispondere a (o intercettare) gli eventi, allora hai bisogno di una lezione. Alcune persone odiano gli UDT (tipi definiti dall’utente) ma mi piacciono, quindi li uso se voglio un codice di auto-documentazione in inglese. Pharmacy.NCPDP è molto più semplice da leggere quindi strPhrmNum 🙂 Ma un UDT è limitato, quindi dico che voglio essere in grado di impostare Pharmacy.NCPDP e avere tutte le altre proprietà. E voglio anche farlo in modo che tu non possa alterare accidentalmente i dati. Quindi ho bisogno di una class, perché non hai proprietà readonly in un UDT, ecc.

Un’altra considerazione è solo una semplice leggibilità. Se stai facendo strutture dati complesse, è spesso utile sapere che devi solo chiamare Company.Owner.Phone.AreaCode e poi cercare di tenere traccia di dove tutto è strutturato. Soprattutto per le persone che devono mantenere quel codebase 2 anni dopo aver lasciato 🙂

Il mio due centesimi è “Codice con scopo”. Non usare una class senza una ragione. Ma se hai una ragione allora fallo 🙂

Uso le classi se voglio creare un pacchetto di codice autoincapsulato che utilizzerò in molti progetti VBA che si presentano per vari client.

È ansible definire una class wrapper sql in accesso più comoda dei recordset e di querydefs. Ad esempio, se si desidera aggiornare una tabella in base a un criterio in un’altra tabella correlata, non è ansible utilizzare i join. Potresti creare un recorset vba e querydef per farlo, ma trovo più semplice con una class. Inoltre, la tua applicazione può avere un concetto che richiede più di 2 tabelle, potrebbe essere meglio usare le classi per questo. Ad esempio, l’applicazione tiene traccia degli incidenti. L’incidente ha diversi attributi che verranno conservati in diverse tabelle {utenti e relativi contatti o profili, descrizione dell’incidente; monitoraggio dello stato; Liste di controllo per aiutare l’ufficiale di supporto a rispondere all’incidente; Rispondere …} . Per tenere traccia di tutte le domande e le relazioni coinvolte, oop può essere utile. È un sollievo essere in grado di fare Incident.Update (xxx) invece di tutta la codifica …

Non vedo perché i criteri per VBA siano diversi da un’altra lingua, in particolare se si fa riferimento a VB.NET.