VBA不支持类多态性,因此建议您改变对员工和经理类的思考方式。您不能将一个员工类作为基类,然后再有一个单独的经理类从员工类派生。它们可以是两个实现共同接口的分离类。稍后我将详细讨论这个问题。现在让我们通过一些例子来说明。
↓ 简单方法 ↓
一个 base
类(Person
),以及从该基类派生的子类。(适用于C#、VB.NET等)
但在VBA中,您需要这样思考:
一个公开枚举属性描述位置的基类。
类似于:
![enter image description here](https://istack.dev59.com/Jov1c.webp)
![enter image description here](https://istack.dev59.com/7ArYQ.webp)
这是暴露一些属性的类最简单的方法。它允许您将
Person
对象添加到集合中,并使用易于使用的
for each
循环和
Intellisense进行迭代!
![enter image description here](https://istack.dev59.com/cfbEL.webp)
属性比较系统将会非常非常容易。
![enter image description here](https://istack.dev59.com/c82bS.webp)
注意:枚举类型同样会被隐式转换为数字。
↓ 更复杂的方法 ↓
有两个不同的类,它们都公开了属性。例如,您有一个名为 Employee
和一个名为 Manager
的类,它们都实现了一个 Person
接口 和一个额外的 Comparer
类,该类公开了一个 Compare()
方法。
![enter image description here](https://istack.dev59.com/GTjM9.webp)
在您的VBA项目中,您需要4个类模块和一个标准模块。
![enter image description here](https://istack.dev59.com/uJaKS.webp)
Person
(这是您的接口)
Public Property Get Name() As String
End Property
Public Property Get Age() As Long
End Property
这个类是接口,
Employee
和
Manager
都需要实现它以共享一些通用函数(获取名称和年龄的getter)。拥有接口允许您使用接口类型变量作为枚举器进行for each循环。您马上会看到。
Employee
和Manager
是相同的。显然,您可以根据实际情况修改它们以适应您的解决方案。
Implements Person
Private name_ As String
Private age_ As Long
Public Property Get Name() As String
Name = name_
End Property
Public Property Let Name(ByVal Value As String)
name_ = Value
End Property
Public Property Get Age() As Long
Age = age_
End Property
Public Property Let Age(ByVal Value As Long)
age_ = Value
End Property
Private Property Get Person_Name() As String
Person_Name = Name
End Property
Private Property Get Person_Age() As Long
Person_Age = Age
End Property
ComparerCls
你将使用此类的实例来比较两个对象的属性或引用。您不一定需要为此创建一个类,但我更喜欢这样做。
Public Enum ComparisonMethod
Names = 0 ' default
Ages = 1
References = 2
End Enum
' makes names the default comparison method
Public Function Compare(ByRef obj1 As Person, _
ByRef obj2 As Person, _
Optional method As ComparisonMethod = 0) _
As Boolean
Select Case method
Case Ages
Compare = IIf(obj1.Age = obj2.Age, True, False)
Case References
Compare = IIf(obj1 Is obj2, True, False)
Case Else
Compare = IIf(obj1.Name = obj2.Name, True, False)
End Select
End Function
和您的Module1
代码
Option Explicit
Sub Main()
Dim emp As New Employee
emp.Name = "person"
emp.Age = 25
Dim man As New Manager
man.Name = "manager"
man.Age = 25
Dim People As New Collection
People.Add emp
People.Add man
Dim individual As Person
For Each individual In People
Debug.Print TypeName(individual), individual.Name, individual.Age
Next
End Sub
运行
Main()
子程序并在
立即窗口中查看结果。
![enter image description here](https://istack.dev59.com/XFwRy.webp)
上述代码的最佳部分是您正在创建一个实现
Person
接口的引用变量。这允许您循环遍历集合中实现该接口的所有项。此外,如果有更多的属性和函数,您可以使用Intellisense,这非常棒。
比较
再次查看ComparerCls
类中的代码
![enter image description here](https://istack.dev59.com/3QWw1.webp)
我希望你现在能理解为什么我要将此分离为一个类。它的目的只是处理对象比较的方式。你可以指定枚举顺序并修改
Compare()
方法本身以不同的方式进行比较。请注意可选参数,它允许您调用 Compare 方法而无需比较方法。
![enter image description here](https://istack.dev59.com/DVTil.webp)
现在,您可以尝试传递不同的参数到比较函数中,并查看结果。请尝试不同的组合:
emp.Name = "name"
man.Name = "name"
Comparer.Compare(emp, name, Names)
Comparer.Compare(emp, name, References)
Comparer.Compare(emp, emp, References)
如果有什么不清楚的地方,请参考
VBA中Implements
关键字的解释。