Domanda

Quando è appropriato usare una classe in Visual Basic, Applications Edition (VBA)?

Suppongo che lo sviluppo accelerato e la riduzione dell'introduzione di bug è un vantaggio comune per la maggior parte delle lingue che supportano OOP. Ma con VBA, esiste un criterio specifico?

È stato utile?

Soluzione

Dipende da chi svilupperà e manterrà il codice. Tipico " Power User " gli autori di macro che hackerano piccole app ad hoc possono essere confusi usando le classi. Ma per uno sviluppo serio, i motivi per usare le lezioni sono gli stessi di altre lingue. Hai le stesse restrizioni di VB6 - nessuna eredità - ma puoi avere polimorfismo usando le interfacce.

Un buon uso delle classi è rappresentare entità e raccolte di entità. Ad esempio, vedo spesso il codice VBA che copia un intervallo di Excel in un array bidimensionale, quindi manipola l'array bidimensionale con 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 un nome appropriato, qualcosa come:

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 è rimuovere la protezione di un foglio di lavoro, eseguire alcune manipolazioni, quindi proteggerlo di nuovo. L'uso di una classe garantisce che il foglio di lavoro sia 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

Puoi quindi usarlo per semplificare il tuo 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 esce, objWorksheetProtector esce dal campo di applicazione e il foglio di lavoro viene nuovamente protetto.

Altri suggerimenti

Penso che i criteri siano gli stessi delle altre lingue

Se devi collegare diversi pezzi di dati e alcuni metodi e anche gestire in modo specifico cosa succede quando l'oggetto viene creato / terminato, le classi sono l'ideale

dì se hai alcune procedure che si attivano quando apri un modulo e uno di essi impiega molto tempo, potresti decidere di voler cronometrare ogni fase ......

È possibile creare una classe di cronometro con metodi per le ovvie funzioni di avvio e arresto, quindi è possibile aggiungere una funzione per recuperare il tempo finora e riportarlo in un file di testo, usando un argomento che rappresenta il nome del processo cronometrato. È possibile scrivere la logica per registrare solo le prestazioni più lente per le indagini.

È quindi possibile aggiungere un oggetto della barra di avanzamento con metodi per aprirlo e chiuderlo e per visualizzare i nomi dell'azione corrente, insieme ai tempi in ms e al tempo probabile rimanente in base ai precedenti rapporti memorizzati ecc.

Un altro esempio potrebbe essere se non ti piace la spazzatura del gruppo di utenti di Access, puoi creare la tua classe utente con metodi di accesso e disconnessione e funzionalità per il controllo dell'accesso degli utenti a livello di gruppo / auditing / registrazione di determinate azioni / errori di tracciamento ecc.

Ovviamente potresti farlo usando una serie di metodi non correlati e un sacco di passaggi variabili, ma avere tutto incapsulato in una classe mi sembra meglio.

Prima o poi ti avvicini ai limiti di VBA, ma è un linguaggio abbastanza potente e se la tua azienda ti lega ad esso puoi effettivamente ottenere alcune soluzioni valide e complesse da esso.

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

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

Mi piace racchiudere la struttura (UDT) e le dichiarazioni della funzione API in una classe CfileDialog. L'evento Class_Initialize imposta i valori predefiniti dei membri della struttura, in modo che quando uso la classe, ho solo bisogno di impostare i membri che voglio cambiare (attraverso le procedure Proprietà). Le costanti di bandiera sono implementate come Enum. Quindi, ad esempio, per scegliere un foglio di calcolo da aprire, il mio codice potrebbe apparire così:

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 classe imposta la directory predefinita su Documenti, sebbene se volessi potrei cambiarla con la proprietà InitDir.

Questo è solo un esempio di come una classe 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 l'aggiunta di astrazione aggiuntiva al di fuori di quel modello di oggetti confonde semplicemente le cose.

Questo non vuol dire che non sia riuscito a trovare un posto utile per una classe in VBA, o fare cose perfettamente utili usando una classe, solo che non le ho mai trovate utili in quell'ambiente.

Puoi anche riutilizzare il codice VBA senza utilizzare le classi effettive. Ad esempio, se si dispone di un chiamato, VBACode. Puoi accedere a qualsiasi funzione o sub in qualsiasi modulo con la seguente sintassi:

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 sostanzialmente che gli oggetti nel tuo sistema saranno meno dipendenti l'uno dall'altro, quindi il refactoring diventa molto più semplice. È possibile ottenere questo è Access utilizzando i moduli di classe. Il rovescio della medaglia è che non è possibile eseguire l'ereditarietà di classe o il polimorfismo in VBA. Alla fine, non ci sono regole rigide e veloci sull'uso delle classi, ma solo le migliori pratiche. Ma tieni presente che man mano che la tua applicazione cresce, più facile è mantenere le classi.

Per la ricorsione dei dati (a.k.a. Gestione della distinta base), una classe personalizzata è estremamente utile e penso che a volte sia indispensabile. È possibile creare una funzione ricorsiva senza un modulo di classe, ma molti problemi relativi ai dati non possono essere risolti in modo efficace.

(Non so perché le persone non vadano a spacciare set di librerie DBA per VBA. Forse gli strumenti XML hanno fatto la differenza.)

Le istanze di moduli multipli sono l'applicazione comune di una classe (molti problemi di automazione sono altrimenti irrisolvibili), presumo che la domanda riguardi le classi personalizzate .

Uso le classi quando devo fare qualcosa e una classe lo farà meglio :) Ad esempio, se devi rispondere (o intercettare) eventi, allora hai bisogno di una classe. Alcune persone odiano gli UDT (tipi definiti dall'utente) ma mi piacciono, quindi li uso se voglio un codice di autocodifica in inglese. Pharmacy.NCPDP è molto più facile da leggere quindi strPhrmNum :) Ma un UDT è limitato, quindi diciamo che voglio essere in grado di impostare Pharmacy.NCPDP e avere tutte le altre proprietà popolate. E voglio anche farlo in modo da non poter modificare accidentalmente i dati. Quindi ho bisogno di una classe, perché non hai proprietà di sola lettura in un UDT, ecc.

Un'altra considerazione è solo la leggibilità semplice. Se stai realizzando strutture di dati complesse, è spesso utile sapere che devi solo chiamare Company.Owner.Phone.AreaCode, quindi provare a tenere traccia di dove tutto è strutturato. Soprattutto per le persone che devono mantenere tale base di codice 2 anni dopo la tua partenza :)

I miei due centesimi sono "Codice con scopo". Non usare una classe senza motivo. Ma se hai un motivo, fallo :)

Uso le classi se voglio creare un pacchetto di codice auto-incapsulato che userò in molti progetti VBA che si presentano per vari client.

È possibile definire una classe wrapper sql in accesso che sia più conveniente di recordset e querydefs. Ad esempio, se si desidera aggiornare una tabella in base a un criterio in un'altra tabella correlata, non è possibile utilizzare i join. Potresti creare un ricorset vba e querydef per farlo, ma lo trovo più facile con una classe. Inoltre, l'applicazione può avere un concetto che richiede più di 2 tabelle, potrebbe essere meglio usare le classi per questo. Per esempio. L'applicazione tiene traccia degli incidenti. L'incidente ha diversi attributi che saranno presenti in diverse tabelle {utenti e loro contatti o profili, descrizione dell'incidente; tracciamento dello stato; Liste di controllo per aiutare l'agente di supporto a rispondere all'incidente; Rispondere ...} . Per tenere traccia di tutte le domande e le relazioni coinvolte, oop può essere utile. È un sollievo poter fare Incident.Update (xxx) invece di tutto il codice ...

Non vedo perché i criteri per VBA sarebbero diversi da un'altra lingua, in particolare se ti riferisci a VB.NET.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top