创建自己的集合类:砖块盖的房子

本主题将继续讨论在“公有集合示例:稻草盖的房子”和“私有集合示例:树枝盖的房子”开始讨论的代码示例。在开始本主题之前,最好阅读那些主题。

实现集合的最强健方法,是使其成为类模块。与前面的示例相比较,将对象创建的所有代码移到集合类中,这就较好符合了面向对象程序设计的原则。

该例使用了跟前面的例子同样的窗体和同样的 Employee 类模块。插入新的类模块,并将其 Name 属性设置为“Employees”。将下面的声明和代码插入到这个新的类模块中。

Option Explicit
Private mcolEmployees As New Collection

Employees 类的 Add、Count 以及 Delete 方法,本质上都跟旧的 SmallBusiness 类中的那些方法是相同的。可以简单地把它们从 SmallBusiness 类模块中删除,然后粘贴到 Employees 类模块中,并更改一下它们的名字。

名字都可以更改,因为不再需要将 EmployeeAdd,比如说,跟 CustomerAdd 区别开来。所实现的每个集合类都有自己的 Add 方法。

'Employees 集合类的方法。
Public Function Add(ByVal Name As String, _
ByVal Salary As Double) As Employee
   Dim empNew As New Employee
   Static intEmpNum As Integer
   ' With 语句,使代码更快,也更简洁
   '.ID 相对 empNew.ID)With empNew
      '为新雇员产生一个唯一的 IDintEmpNum = intEmpNum + 1
      .ID = "E" & Format$(intEmpNum, "00000")
      .Name = Name
      .Salary = Salary
      ' Employee 对象引用添加到集合中,
      ' ID 属性作为键。
      mcolEmployees.Add empNew, .ID
   End With
   '为新的 Employee 返回一个引用。
   Set Add = empNew
End Function

Public Function Count() As Long
   Count = mcolEmployees.Count
End Function

Public Sub Delete(ByVal Index As Variant)
   mcolEmployees.Remove Index
End Sub

SmallBusiness 对象的 Employees 方法变成了集合类中的 Item 方法。为了通过索引或者键来检索成员,它仍然委派 Collection 对象为代表。

'Employees 集合类的方法。
Public Function Item(ByVal Index As Variant) _
As Employee
   Set Item = mcolEmployees.Item(Index)
End Function

可以在这里添加一个很好的技巧。通过将 Item 设置为 Employees 类的缺省方法,就得到了为 Employees("E00001") 编写代码的能力,就象用 Collection 对象做的一样。

要使 Item 成为缺省的属性,请按照以下步骤执行:

  1. “工具”菜单上,单击“过程属性”,打开“过程属性”对话框。在“名称”框中,选择 Item 方法。

  2. 单击“高级”,显示高级功能。在“过程标识符”框中,选择“(缺省)”,使 Item 方法成为缺省的。单击“确定”

注意   一个类只能有一个缺省成员(属性或者方法)。

使 For Each ... Next 有效

伴随着强健性而来的,是重新获得了 For Each ... Next。通过添加下面的方法,可以再一次将所有工作委派给 Collection 对象:

'NewEnum 必须返回一个集合的枚举算子的 IUnknown 接口。
Public Function NewEnum() As IUnknown
   Set NewEnum = mcolEmployees.[_NewEnum]
End Function

委派给 Collection 对象的最重要的东西是它的枚举算子。枚举算子是一个小对象,该对象知道如何遍历集合中的各项。不能用 Visual Basic 来书写枚举算子对象,因为 Employees 类是基于 Collection 对象的,可以返回 Collection 对象的枚举算子—它自然知道如何枚举 Collection 对象所保存的各项。

包围 Collection 对象的 _NewEnum 方法的方括号是必要的,这是因为方法名前面的下划线。前面的这个下划线是一个约定,它指明该方法是隐藏在类型库中的。不能把自己的方法命名为 _NewEnum,但是可以把它隐藏在类型库中,并将 For Each ... Next 所需要的过程 ID 赋给它。

要隐藏 NewEnum 方法,并将所需的过程 ID 赋给它,请按照以下步骤执行:

  1. “工具”菜单上,单击“过程属性”,打开“过程属性”对话框,在“名称”框中,选择 NewEnum 方法。

  2. 单击“高级”,显示一些高级功能。选中“隐藏该成员”,使 NewEnum 隐藏在类型库中。

  3. “过程标识符”框中,键入 -4,将 For Each ... Next 所需要的过程标识符赋给 NewEnum。单击“确定”

重点   为了使自己的集合类使用 For Each ... Next 来工作,必须提供有正确过程标识符的隐藏 NewEnum 方法。

SmallBusiness 类留下的东西不多了

到现在为止,SmallBusiness 类中还只有相当少的代码。为了取代所删除了的 Collection 对象和所有方法,有新的声明和只读属性:

Option Explicit
Private mEmployees As New Employees

Public Property Get Employees() As Employees
   Set Employees = mEmployees
End If

这需要简单解释一下。假设曾经省略了 Property Get,那么可以简单地声明 Public Employees As New Employees

只要没有人犯什么错误,每件事物都将很好地工作,但是如果偶然编写代码为 Set sbMain.Employees = Nothing,将会发生什么情况?对,Employees 集合将被撤消。若是将 Employees 设置为只读属性,则可以避免这种可能性。

对窗体的改动

窗体模块的代码跟前面示例中的非常类似。可用模块级相同的声明,而且“关闭”按钮的 Click 事件也是同样的。

在大多数事件过程中的唯一改动是:用 Employees 集合对象的新方法取代 SmallBusiness 类的旧方法:

Private Sub cmdEmployeeAdd_Click()
   sbMain.Employees.Add txtName.Text, txtSalary.Text
   txtName.Text = ""
   txtSalary.Text = ""
   cmdListEmployees.Value = True
End Sub

Private Sub cmdEmployeeDelete_Click()
   '检查一下,以确保有雇员被选中。
   If lstEmployees.ListIndex > -1 Then
      '前六个字符是 IDsbMain.Employees.Delete _
      Left(lstEmployees.Text, 6)
   End If
   cmdListEmployees.Value = True
End Sub

Private Sub cmdListEmployees_Click()
   Dim emp As Employee
   lstEmployees.Clear
   For Each emp In sbMain.Employees
      lstEmployees.AddItem emp.ID & ", " & emp.Name _
      & ", " & emp.Salary
   Next
End Sub

注意,又可以用 For Each ... Next 来列出雇员了。

运行该工程,并验证每件事物都能正常工作。这次“有问题”按钮没有任何代码,因为封装已经消除了问题。

详细信息   为了得到关于背景集合的信息,请阅读“Visual Basic 集合对象”和“Visual Basic 集合”。

在专业版和企业版中,包括了 Class Builder 实用工具,该实用工具可以创建集合类。

稻草盖的房子、树枝盖的房子以及砖块盖的房子的示例课程部分,在下面的“好的面向对象程序设计的优点”中作了总结。