Question

Quand est-il approprié d'utiliser une classe dans Visual Basic pour Applications (VBA)?

J'assume le développement accéléré et réduction du nombre de bogues introduits . un avantage commun pour la plupart des langues prenant en charge la POO. Mais avec VBA, existe-t-il un critère spécifique?

Était-ce utile?

La solution

Cela dépend de qui va développer et maintenir le code. Typique "Utilisateur privilégié" Les auteurs de macros qui piratent de petites applications ad-hoc risquent d’être confus en utilisant des classes. Mais pour un développement sérieux, les raisons d'utiliser des classes sont les mêmes que dans d'autres langues. Vous avez les mêmes restrictions que VB6 - pas d'héritage - mais vous pouvez avoir un polymorphisme en utilisant des interfaces.

Une bonne utilisation des classes est de représenter des entités et des ensembles d’entités. Par exemple, je vois souvent du code VBA qui copie une plage Excel dans un tableau à deux dimensions, puis manipule le tableau à deux dimensions avec un code tel que:

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

Il est plus facile de copier la plage dans une collection d'objets dotés de propriétés nommées, comme par exemple:

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

Un autre exemple consiste à utiliser des classes pour implémenter le modèle de conception RAII (google pour celui-ci). Par exemple, une chose que je devrais faire est de déprotéger une feuille de travail, de faire quelques manipulations, puis de la protéger à nouveau. L'utilisation d'une classe garantit que la feuille de calcul sera toujours protégée à nouveau, même en cas d'erreur dans votre code:

--- 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

Vous pouvez ensuite l'utiliser pour simplifier votre code:

Public Sub DoSomething()
   Dim objWorksheetProtector as WorksheetProtector
   Set objWorksheetProtector = New WorksheetProtector
   objWorksheetProtector.Unprotect myWorksheet, myPassword

   ... manipulate myWorksheet - may raise an error

End Sub 

À la fermeture de ce sous-objet, objWorksheetProtector sort du cadre et la feuille de calcul est à nouveau protégée.

Autres conseils

Je pense que les critères sont les mêmes que ceux des autres langues

Si vous devez associer plusieurs éléments de données et certaines méthodes et gérer spécifiquement ce qui se passe lorsque l'objet est créé / terminé, les classes sont idéales

Si vous avez quelques procédures qui se déclenchent lorsque vous ouvrez un formulaire et que l’une d’elles prend beaucoup de temps, vous pouvez décider de chronométrer chaque étape ......

Vous pouvez créer une classe de chronomètre avec des méthodes pour les fonctions évidentes de démarrage et d'arrêt, vous pouvez ensuite ajouter une fonction permettant de récupérer l'heure et de la signaler dans un fichier texte, en utilisant un argument représentant le nom du processus en cours. chronométré. Vous pouvez écrire une logique pour consigner uniquement les performances les plus lentes à des fins d’investigation.

Vous pouvez ensuite ajouter un objet de barre de progression avec des méthodes pour l'ouvrir et le fermer et afficher les noms de l'action en cours, ainsi que les temps en ms et le temps restant probablement basé sur les rapports stockés précédents, etc.

Un autre exemple pourrait être que si vous n'aimiez pas les déchets du groupe d'utilisateurs d'Access, vous pouvez créer votre propre classe User avec des méthodes de connexion et de déconnexion et des fonctionnalités pour le contrôle / l'audit de l'accès des utilisateurs au niveau du groupe / la consignation de certaines actions / erreurs de suivi, etc.

Bien sûr, vous pouvez le faire en utilisant un ensemble de méthodes sans rapport et beaucoup de variables, mais le fait de tout encapsuler dans une classe me semble simplement préférable.

Tôt ou tard, vous approchez des limites de VBA, mais c'est un langage assez puissant et si votre entreprise vous y lie, vous pouvez réellement en tirer de bonnes solutions complexes.

Les classes sont extrêmement utiles pour traiter les fonctions plus complexes de l'API, et en particulier lorsqu'elles nécessitent une structure de données.

Par exemple, les fonctions GetOpenFileName () et GetSaveFileName () prennent une structure OPENFILENAME avec plusieurs membres. vous n’aurez peut-être pas besoin de tous les exploiter, mais ils sont là et devraient être initialisés.

J'aime envelopper la déclaration de structure (UDT) et la fonction API dans une classe CfileDialog. L'événement Class_Initialize définit les valeurs par défaut des membres de la structure. Ainsi, lorsque j'utilise la classe, je ne dois définir que les membres à modifier (via les procédures Property). Les constantes d'indicateur sont implémentées sous forme d'énumération. Ainsi, par exemple, pour choisir une feuille de calcul à ouvrir, mon code pourrait ressembler à ceci:

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 définit le répertoire par défaut sur Mes documents, mais si je le voulais, je pourrais le changer avec la propriété InitDir.

Ceci n'est qu'un exemple de la manière dont une classe peut être extrêmement bénéfique dans une application VBA.

Je ne dirais pas qu'il existe un critère spécifique, mais je n'ai jamais vraiment trouvé d'endroit utile pour utiliser Classes dans le code VBA. Dans mon esprit, cela est tellement lié aux modèles existants autour des applications Office que l'ajout d'une abstraction supplémentaire en dehors de ce modèle d'objet est source de confusion.

Cela ne veut pas dire qu’un ne pourrait pas trouver une place utile pour un cours dans VBA, ou faire des choses parfaitement utiles en utilisant un cours, mais je ne les ai jamais trouvées utiles dans cet environnement.

Vous pouvez également réutiliser le code VBA sans utiliser les classes réelles. Par exemple, si vous avez un appelé, VBACode. Vous pouvez accéder à n’importe quelle fonction ou sous-fonction de n’importe quel module avec la syntaxe suivante:

VBCode.mysub(param1, param2)

Si vous créez une référence à un modèle / doc (comme une dll), vous pouvez référencer le code d'autres projets de la même manière.

Développer des logiciels, même avec Microsoft Access, en utilisant la programmation orientée objet est généralement une bonne pratique. Cela permettra une évolutivité future en permettant aux objets d'être couplés de manière lâche, avec de nombreux avantages. Cela signifie essentiellement que les objets de votre système seront moins dépendants les uns des autres. Le refactoring devient donc beaucoup plus facile. Vous pouvez y parvenir grâce à l'accès via Class Modules. L'inconvénient est que vous ne pouvez pas effectuer l'héritage de classe ou le polymorphisme dans VBA. En fin de compte, il n'y a pas de règle absolue sur l'utilisation de classes, mais simplement sur les meilleures pratiques. Mais gardez à l'esprit que plus votre application grandit, plus il est facile de maintenir l'utilisation des classes.

Pour la récursivité des données (traitement des nomenclatures, par exemple), une classe personnalisée est extrêmement utile et, parfois, indispensable. Vous pouvez créer une fonction récursive sans module de classe, mais de nombreux problèmes de données ne peuvent pas être résolus efficacement.

(Je ne sais pas pourquoi les gens ne vendent pas des ensembles de bibliothèques de nomenclature pour VBA. Peut-être que les outils XML ont fait une différence.)

Les instances de formulaire multiples sont l'application courante d'une classe (de nombreux problèmes d'automatisation sont autrement insolubles), je suppose que la question concerne les classes personnalisées .

J'utilise des classes lorsque j'ai besoin de faire quelque chose et une classe le fera mieux :) Par exemple, si vous devez répondre à (ou intercepter) des événements, alors vous avez besoin d'une classe. Certaines personnes détestent les UDT (types définis par l'utilisateur) mais je les aime bien, donc je les utilise si je veux du code auto-documenté en anglais clair. Pharmacy.NCPDP étant beaucoup plus facile à lire que strPhrmNum :) Mais un UDT est limité, alors disons que je veux pouvoir définir Pharmacy.NCPDP et que toutes les autres propriétés sont remplies. Et je veux aussi le faire pour que vous ne puissiez pas modifier accidentellement les données Ensuite, j'ai besoin d'une classe, car vous n'avez pas de propriétés en lecture seule dans un UDT, etc.

Une autre considération est la simple lisibilité. Si vous utilisez des structures de données complexes, il est souvent utile de savoir que vous devez simplement appeler Company.Owner.Phone.AreaCode pour essayer de savoir où tout est structuré. Surtout pour les personnes qui doivent maintenir cette base de code 2 ans après votre départ:)

Mes deux cents sont "Code avec objectif". Ne pas utiliser une classe sans raison. Mais si vous avez une raison, faites-le:)

J'utilise des classes si je veux créer un paquet de code auto-encapsulé que je vais utiliser dans de nombreux projets VBA rencontrés par différents clients.

Vous pouvez définir une classe d’encapsuleur SQL plus accessible que les jeux d’enregistrements et querydefs. Par exemple, si vous souhaitez mettre à jour une table en fonction d'un critère dans une autre table liée, vous ne pouvez pas utiliser de jointure. Vous pouvez construire un recorset vba et querydef pour le faire, mais je le trouve plus facile avec une classe. En outre, votre application peut avoir un concept qui nécessite plus de 2 tables, il serait peut-être préférable d'utiliser des classes pour cela. Par exemple. Vous application suivre les incidents. Incident a plusieurs attributs qui seront conservés dans plusieurs tables {utilisateurs et leurs contacts ou profils, description de l'incident; suivi de l'état; Des listes de contrôle pour aider l'agent d'assistance à répondre à l'incident; Répondre ...} . Pour garder une trace de toutes les requêtes et relations impliquées, oop peut être utile. C'est un soulagement de pouvoir utiliser Incident.Update (xxx) au lieu de tout le codage ...

Je ne vois pas pourquoi les critères de VBA seraient différents de ceux d'une autre langue, en particulier si vous faites référence à VB.NET.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top