When to use a Class in VBA?

后端 未结 12 1086
情歌与酒
情歌与酒 2020-12-02 07:04

When is it appropriate to use a class in Visual Basic for Applications (VBA)?

I\'m assuming the accelerated development and reduction of introducing bugs is a common

相关标签:
12条回答
  • 2020-12-02 07:41

    I wouldn't say there's a specific criterion, but I've never really found a useful place to use Classes in VBA code. In my mind it's so tied to the existing models around the Office apps that adding additional abstraction outside of that object model just confuses things.

    That's not to say one couldn't find a useful place for a class in VBA, or do perfectly useful things using a class, just that I've never found them useful in that environment.

    0 讨论(0)
  • 2020-12-02 07:43

    It depends on who's going to develop and maintain the code. Typical "Power User" macro writers hacking small ad-hoc apps may well be confused by using classes. But for serious development, the reasons to use classes are the same as in other languages. You have the same restrictions as VB6 - no inheritance - but you can have polymorphism by using interfaces.

    A good use of classes is to represent entities, and collections of entities. For example, I often see VBA code that copies an Excel range into a two-dimensional array, then manipulates the two dimensional array with code like:

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

    It's more readable to copy the range into a collection of objects with appropriately-named properties, something like:

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

    Another example is to use classes to implement the RAII design pattern (google for it). For example, one thing I may need to do is to unprotect a worksheet, do some manipulations, then protect it again. Using a class ensures that the worksheet will always be protected again even if an error occurs in your 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
    

    You can then use this to simplify your code:

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

    When this Sub exits, objWorksheetProtector goes out of scope, and the worksheet is protected again.

    0 讨论(0)
  • 2020-12-02 07:44

    I use classes when I need to do something and a class will do it best:) For instance if you need to respond to (or intercept) events, then you need a class. Some people hate UDTs (user defined types) but I like them, so I use them if I want plain-english self-documenting code. Pharmacy.NCPDP being a lot easier to read then strPhrmNum :) But a UDT is limited, so say I want to be able to set Pharmacy.NCPDP and have all the other properties populate. And I also want make it so you can't accidentally alter the data. Then I need a class, because you don't have readonly properties in a UDT, etc.

    Another consideration is just simple readability. If you are doing complex data structures, it's often beneficial to know you just need to call Company.Owner.Phone.AreaCode then trying to keep track of where everything is structured. Especially for people who have to maintain that codebase 2 years after you left:)

    My own two cents is "Code With Purpose". Don't use a class without a reason. But if you have a reason then do it:)

    0 讨论(0)
  • 2020-12-02 07:44

    Developing software, even with Microsoft Access, using Object Oriented Programming is generally a good practice. It will allow for scalability in the future by allowing objects to be loosely coupled, along with a number of advantages. This basically means that the objects in your system will be less dependent on each other, so refactoring becomes a lot easier. You can achieve this is Access using Class Modules. The downside is that you cannot perform Class Inheritance or Polymorphism in VBA. In the end, there's no hard and fast rule about using classes, just best practices. But keep in mind that as your application grows, the easier it is to maintain using classes.

    0 讨论(0)
  • 2020-12-02 07:45

    You can define a sql wrapper class in access that is more convenient than the recordsets and querydefs. For example if you want to update a table based on a criteria in another related table, you cannot use joins. You could built a vba recorset and querydef to do that however i find it easier with a class. Also, your application can have some concept that need more that 2 tables, it might be better imo to use classes for that. E.g. You application track incidents. Incident have several attributes that will hold in several tables {users and their contacts or profiles, incident description; status tracking; Checklists to help the support officer to reply tonthe incident; Reply ...} . To keep track of all the queries and relationships involved, oop can be helpful. It is a relief to be able to do Incident.Update(xxx) instead of all the coding ...

    0 讨论(0)
  • 2020-12-02 07:49

    As there is a lot code overhead in using classes in VBA I think a class has to provide more benefit than in other languages:

    So this are things to consider before using a class instead of functions:

    • There is no class-inheritance in vba. So prepare to copy some code when you do similar small things in different classes. This happens especially when you want to work with interfaces and want to implement one interfaces in different classes.

    • There are no built in constructors in vba-classes. In my case I create a extra function like below to simulate this. But of curse, this is overhead too and can be ignored by the one how uses the class. Plus: As its not possible to use different functions with the same name but different parameters, you have to use different names for your "constructor"-functions. Also the functions lead to an extra debug-step which can be quite annoying.

    Public Function MyClass(ByVal someInit As Boolean) As MyClassClass Set MyClass = New MyClassClass Call MyClass.Init(someInit) End Function
    • The development environment does not provide a "goto definition" for class-names. This can be quite annoying, especially when using classes with interfaces, because you always have to use the module-explorer to jump to the class code.

    • object-variables are used different to other variable-types in different places. So you have to use a extra "Set" to assign a object

    Set varName = new ClassName

    • if you want to use properties with objects this is done by a different setter. You have to use "set" instead of "let"

    • If you implement an interface in vba the function-name is named "InterfaceName_functionName" and defined as private. So you can use the interface function only when you cast the Variable to the Interface. If you want to use the function with the original class, you have to create an extra "public" function which only calls the interface function (see below). This creates an extra debug-step too.

    'content of class-module: MyClass implements IMyInterface private sub IMyInterface_SomeFunction() 'This can only be called if you got an object of type "IMyInterface" end function private sub IMyInterface_SomeFunction() 'You need this to call the function when having an object of the type "MyClass" Call IMyInterface_SomeFunction() end function

    This means:

    • I !dont! use classes when they would contain no member-variables.
    • I am aware of the overhead and dont use classes as the default to do things. Usually functions-only is the default way to do things in VBA.

    Examples of classes I created which I found to be useful:

    • Collection-Classes: e.g. StringCollection, LongCollection which provide the collection functionality vba is missing
    • DbInserter-Class: Class to create insert-statements

    Examples of classes I created which I dont found to be useful:

    • Converter-class: A class which would have provided the functionality for converting variables to other types (e.g. StringToLong, VariantToString)
    • StringTool-class: A class which would have provided some functionality for strings. e.g. StartsWith
    0 讨论(0)
提交回复
热议问题