Excel 在VBA中使用类的好处是什么?

Excel 在VBA中使用类的好处是什么?,excel,vba,class,Excel,Vba,Class,我正在Excel中进行VBA编程,有一个工作簿,其中所有的数据表都将复制到另一个工作表中。新的工作表将有几个标题行,我想保持他们所在的位置跟踪,所以我不必经常在他们找到字 在Excel工作簿打开时使用类并使其保持运行最简单的方法是什么?或者这会使它变得沉重和难以处理,我应该继续使用子程序吗?使用类的好处是什么?这不像我有几个对象,只有表和列上的验证。如果有很多子例程或子例程很长,那么将代码构造成类可能会有所帮助。如果只有两个子例程,比如说,每一个子例程都只有10行代码,那么这就太过分了。将代码组

我正在Excel中进行VBA编程,有一个工作簿,其中所有的数据表都将复制到另一个工作表中。新的工作表将有几个标题行,我想保持他们所在的位置跟踪,所以我不必经常在他们找到字


在Excel工作簿打开时使用类并使其保持运行最简单的方法是什么?或者这会使它变得沉重和难以处理,我应该继续使用子程序吗?使用类的好处是什么?这不像我有几个对象,只有表和列上的验证。

如果有很多子例程或子例程很长,那么将代码构造成类可能会有所帮助。如果只有两个子例程,比如说,每一个子例程都只有10行代码,那么这就太过分了。将代码组织到类中的好处是,当您回到后面的代码时,它更易于阅读和更改。因此,将代码结构化为类的另一个原因是,如果代码可能需要更改,那么使用类而不仅仅是子例程的优势在于,类创建了一个抽象级别,允许您编写更干净的代码。诚然,如果您以前从未在VBA中使用过类,那么会有一个学习曲线,但我相信花时间来解决这个问题肯定是值得的

您应该切换到类的一个关键指示是,您是否在不断地向函数和子例程添加参数。在这种情况下,几乎总是最好使用类

我复制了以下内容中的课程说明:


下面是一个很长的示例,说明了使用类可以如何帮助您。虽然这个示例很长,但它将向您展示一些面向对象编程的原则如何真正帮助您清理代码

在VBA编辑器中,转至
Insert>Class模块
。在属性窗口(默认情况下,屏幕左下角)中,将模块名称更改为
WorkLogItem
。将以下代码添加到类中:

Option Explicit

Private pTaskID As Long
Private pPersonName As String
Private pHoursWorked As Double

Public Property Get TaskID() As Long
    TaskID = pTaskID
End Property

Public Property Let TaskID(lTaskID As Long)
    pTaskID = lTaskID
End Property

Public Property Get PersonName() As String
    PersonName = pPersonName
End Property

Public Property Let PersonName(lPersonName As String)
    pPersonName = lPersonName
End Property

Public Property Get HoursWorked() As Double
    HoursWorked = pHoursWorked
End Property

Public Property Let HoursWorked(lHoursWorked As Double)
    pHoursWorked = lHoursWorked
End Property
上面的代码将为我们提供一个强类型对象,它特定于我们处理的数据。使用多维数组存储数据时,代码类似于此:
arr(1,1)
是ID,
arr(1,2)
是人名,
arr(1,3)
是工时。使用这种语法,很难知道什么是什么。让我们假设您仍然将对象加载到数组中,而是使用上面创建的
WorkLogItem
。如果使用此名称,您可以执行
arr(1).PersonName
来获取此人的姓名。这使您的代码更易于阅读

让我们继续这个例子。我们将尝试使用
集合
,而不是将对象存储在数组中

接下来,添加一个新的类模块并将其称为
ProcessWorkLog
。将以下代码放入其中:

Option Explicit

Private pWorkLogItems As Collection

Public Property Get WorkLogItems() As Collection
    Set WorkLogItems = pWorkLogItems
End Property

Public Property Set WorkLogItems(lWorkLogItem As Collection)
    Set pWorkLogItems = lWorkLogItem
End Property

Function GetHoursWorked(strPersonName As String) As Double
    On Error GoTo Handle_Errors
    Dim wli As WorkLogItem
    Dim doubleTotal As Double
    doubleTotal = 0
    For Each wli In WorkLogItems
        If strPersonName = wli.PersonName Then
            doubleTotal = doubleTotal + wli.HoursWorked
        End If
    Next wli

Exit_Here:
    GetHoursWorked = doubleTotal
        Exit Function

Handle_Errors:
        'You will probably want to catch the error that will '
        'occur if WorkLogItems has not been set '
        Resume Exit_Here


End Function
上面的类将用于使用
WorkLogItem
的集合“做点什么”。最初,我们只是将其设置为计算总工作小时数。让我们测试一下我们编写的代码。创建一个新模块(这次不是类模块;只是一个“常规”模块)。在模块中粘贴以下代码:

Option Explicit

Function PopulateArray() As Collection
    Dim clnWlis As Collection
    Dim wli As WorkLogItem
    'Put some data in the collection'
    Set clnWlis = New Collection

    Set wli = New WorkLogItem
    wli.TaskID = 1
    wli.PersonName = "Fred"
    wli.HoursWorked = 4.5
    clnWlis.Add wli

    Set wli = New WorkLogItem
    wli.TaskID = 2
    wli.PersonName = "Sally"
    wli.HoursWorked = 3
    clnWlis.Add wli

    Set wli = New WorkLogItem
    wli.TaskID = 3
    wli.PersonName = "Fred"
    wli.HoursWorked = 2.5
    clnWlis.Add wli

    Set PopulateArray = clnWlis
End Function

Sub TestGetHoursWorked()
    Dim pwl As ProcessWorkLog
    Dim arrWli() As WorkLogItem
    Set pwl = New ProcessWorkLog
    Set pwl.WorkLogItems = PopulateArray()
    Debug.Print pwl.GetHoursWorked("Fred")

End Sub
在上面的代码中,
PopulateArray()
只是创建了一个
WorkLogItem
的集合。在实际代码中,可以创建类来解析Excel工作表或数据对象以填充集合或数组

TestGetHoursWorked()
代码只是演示了如何使用这些类。您注意到,
ProcessWorkLog
被实例化为一个对象。实例化后,
WorkLogItem
的集合将成为
pwl
对象的一部分。您在
Set pwl.WorkLogItems=PopulateArray()
行中注意到了这一点。接下来,我们只需调用我们编写的函数,该函数作用于集合
worklogitem

这为什么有用

假设您的数据发生了更改,并且希望添加一个新方法。假设您的
WorkLogItem
现在包含一个用于
HoursOnBreak
的字段,您希望添加一个新方法来计算该字段

您只需向
WorkLogItem
添加一个属性,如下所示:

Private pHoursOnBreak As Double

Public Property Get HoursOnBreak() As Double
    HoursOnBreak = pHoursOnBreak
End Property

Public Property Let HoursOnBreak(lHoursOnBreak As Double)
    pHoursOnBreak = lHoursOnBreak
End Property
当然,您需要更改填充集合的方法(我使用的示例方法是
PopulateArray()
,但您可能应该为此使用单独的类)。然后,只需将新方法添加到
ProcessWorkLog
类:

Function GetHoursOnBreak(strPersonName As String) As Double
     'Code to get hours on break
End Function
现在,如果我们想更新
TestGetHoursWorked()
方法以返回
GetHoursOnBreak
的结果,我们只需添加以下行:

    Debug.Print pwl.GetHoursOnBreak("Fred")
如果传入一个表示数据的值数组,则必须找到代码中使用这些数组的每个位置,然后相应地进行更新。如果改用类(及其实例化对象),则可以更轻松地更新代码以处理更改。此外,当您允许以多种方式使用该类时(可能一个函数只需要4个对象属性,而另一个函数需要6个),它们仍然可以引用同一个对象。这样可以避免为不同类型的函数使用多个数组


为了进一步阅读,我强烈建议您购买一份。这本书充满了伟大的例子和最佳实践以及大量的示例代码。如果您为一个严肃的项目在VBA上投入了大量时间,那么花时间阅读这本书是非常值得的

除了其他撰稿人所说的优点之外,还有一件事你可以补充(抱歉,如果这是本·麦科马克(Ben McCormack)的优秀答案中的某个地方,我错过了)。如果您的VBA脚本可能在某个时候被重新编程,则类可以有其用途

例如,我正在设计一种订单管理系统。它将由