什么时候在VBA中使用类?
什么时候适合在Visual Basic for Applications(VBA)中使用类?
我认为对于大多数支持OOP的语言来说,加速开发和减少引入错误是一个共同的好处。但是对于VBA,是否有特定标准?
解决方案
我看不出为什么VBA的标准与另一种语言会有所不同,尤其是在我们指的是VB.NET时。
我不会说有一个特定的标准,但是我从来没有真正找到过在VBA代码中使用类的有用地方。在我看来,它与Office应用程序周围的现有模型紧密相关,以至于在该对象模型之外添加其他抽象只会使事情变得混乱。
这并不是说无法在VBA中为类找到有用的地方,或者使用类不能做完全有用的事情,只是我从未发现它们在那种环境中有用。
我们也可以在不使用实际类的情况下重用VBA代码。例如,如果我们有一个被调用的VBACode。我们可以使用以下语法访问任何模块中的任何函数或者子:
VBCode.mysub(param1, param2)
如果创建对模板/文档的引用(就像对dll一样),则可以以相同的方式引用其他项目中的代码。
我认为标准与其他语言相同
如果我们需要将多个数据和某些方法结合在一起,并且还专门处理创建/终止对象时发生的情况,则类是理想的选择
假设如果我们有一些打开表单时会触发的过程,而其中一个过程花费的时间很长,那么我们可能会决定要为每个阶段计时。
我们可以创建一个带有用于启动和停止的明显函数的方法的秒表类,然后可以添加一个函数以检索到目前为止的时间,并使用表示正在计时的进程名称的参数在文本文件中报告该时间。我们可以编写逻辑以仅记录最慢的性能以进行调查。
然后,我们可以添加带有方法的进度条对象,以打开和关闭该对象以及显示当前操作的名称,以及基于以前存储的报告的时间(以毫秒为单位)和可能的剩余时间等
另一个示例可能是,如果我们不喜欢Access的用户组垃圾,则可以使用登录和注销方法以及组级用户访问控制/审核/记录某些操作/跟踪错误等功能创建自己的User类。
当然,我们可以使用一组不相关的方法和大量的变量传递来做到这一点,但是对我来说,将它们全部封装在一个类中似乎更好。
我们迟早会接近VBA的极限,但是它是一种非常强大的语言,如果公司将它与VBA绑定在一起,则实际上可以从中获得一些好的,复杂的解决方案。
通常,使用面向对象编程来开发软件,甚至使用Microsoft Access,也是一种好的做法。通过允许对象松散耦合,它将在将来实现可伸缩性,同时具有许多优点。从根本上讲,这意味着系统中的对象之间的依赖程度将降低,因此重构变得更加容易。我们可以通过使用类模块进行访问来实现。缺点是我们不能在VBA中执行类继承或者多态。最后,关于使用类,没有硬性规定,只有最佳实践。但是请记住,随着应用程序的增长,使用类进行维护变得更加容易。
这取决于谁来开发和维护代码。典型的"超级用户"宏编写者会通过使用类来混淆小型的即席应用程序。但是对于认真的开发,使用类的原因与其他语言相同。我们具有与VB6无继承相同的限制,但可以通过使用接口来实现多态。
类的一种好用法是表示实体和实体的集合。例如,我经常看到VBA代码将Excel范围复制到二维数组中,然后使用如下代码处理二维数组:
Total = 0 For i = 0 To NumRows-1 Total = Total + (OrderArray(i,1) * OrderArray(i,3)) Next i
将范围复制到具有适当命名的属性的对象的集合中更容易理解,例如:
Total = 0 For Each objOrder in colOrders Total = Total + objOrder.Quantity * objOrder.Price Next i
另一个示例是使用类来实现RAII设计模式(适用于Google)。例如,我可能需要做的一件事是取消保护工作表,进行一些操作,然后再次保护它。使用类可确保即使在代码中发生错误,工作表也将始终受到再次保护:
--- 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
然后,我们可以使用它来简化代码:
Public Sub DoSomething() Dim objWorksheetProtector as WorksheetProtector Set objWorksheetProtector = New WorksheetProtector objWorksheetProtector.Unprotect myWorksheet, myPassword ... manipulate myWorksheet - may raise an error End Sub
当此Sub退出时,objWorksheetProtector超出范围,工作表再次受到保护。
对于数据递归(也称为BOM表处理),自定义类非常有帮助,我认为有时必不可少。我们可以在没有类模块的情况下创建递归函数,但是许多数据问题无法有效解决。
(我不知道为什么人们不为VBA兜售BOM库集。也许XML工具有所作为。)
多个表单实例是类的常见应用程序(许多自动化问题否则无法解决),我假设问题与自定义类有关。
当我需要做某事时,我会使用类,而一个类会做得最好:)例如,如果我们需要响应(或者拦截)事件,则需要一个类。有些人讨厌UDT(用户定义的类型),但我喜欢它们,因此如果我想要纯英语的自我记录代码,则可以使用它们。 Pharmacy.NCPDP比strPhrmNum更容易阅读:)但是UDT受到限制,所以说我希望能够设置Pharmacy.NCPDP并填充所有其他属性。而且我也想做到这一点,以便我们不会意外更改数据。然后,我需要一个类,因为我们在UDT等中没有只读属性。
另一个考虑因素只是简单的可读性。如果我们要处理复杂的数据结构,那么知道只需要调用Company.Owner.Phone.AreaCode然后尝试跟踪所有内容的结构通常是有益的。特别是对于那些在我们离开两年后必须维护该代码库的人:)
我自己的两分钱是"有目的的代码"。不要无缘无故地使用课程。但是,如果我们有理由,请这样做:)