公有集合示例:稻草盖的房子

为了创建此示例,打开一个新工程并插入两个类模块。在窗体上画出五个命令按钮、一个列表框、两个文本框,以及两个标签,如图 9.13 所示。

图 9.13   Employees 集合示例

下表列出了该示例所需设置的属性值。

对象 属性 设置值
类模块 Name Employee
类模块 Name SmallBusiness
窗体 Caption 雇员集合
第一个命令按钮 Caption
Name
添加
cmdAddEmployee
第二个命令按钮 Caption
Name
删除
cmdDeleteEmployee
第三个命令按钮 Caption
Name
刷新表
cmdListEmployees
第四个命令按钮 Caption
Name
有问题
cmdTrouble
第五个命令按钮 Caption
Name
关闭
cmdClose
第一个标签控件 Caption Name
第二个标签控件 Caption Salary
第一个文本框 Name
Text
txtName
(blank)
第二个文本框 Name
Text
txtSalary
(blank)
列表框 Name lstEmployees

在 Employee 类模块中,将下面的声明和属性过程添加进去:

Option Explicit
'Employee 类的属性。
Public Name As String
Public Salary As Long   

'只写一次 ID 属性的私有数据。
Private mstrID As String

Property Get ID() As String
   ID = mstrID
End Property

'首次设置 ID 属性时,静态的 Boolean 变量也要设置。
'后续的调用什么也不做。
'(若不是这样,产生一个错误会更好。)
Property Let ID(strNew As String)
   Static blnAlreadySet As Boolean
   If Not blnAlreadySet Then
      blnAlreadySet = True
      mstrID = strNew
   End If
End Property

ID 属性是从集合中检索或者删除 Employee 对象的键,因此必须对它进行一次性设置并不再更改。这是用 Static Boolean 变量来完成的,该变量在首次设置 ID 属性的时候被设置为 True。该属性总是可读的,因为有一个 Property Get。

在 SmallBusiness 类模块中,将下面的声明添加进去。当代码中引用 Employees 变量时,将创建集合对象。

Option Explicit
Public Employees As New Collection

窗体所做的所有工作

所有的剩余代码都在窗体模块中。在声明部分添加下面的声明。

Option Explicit
Public sbMain As New SmallBusiness

cmdEmployeeAdd_Click 事件中的代码,将一个成员添加到集合。

Private Sub cmdEmployeeAdd_Click()
   Dim empNew As New Employee
   Static intEmpNum As Integer
   ' With 语句,使代码更快,也更简洁
   '.ID 对应 empNew.ID)With empNew
      '为新的雇员产生一个唯一的 IDintEmpNum = intEmpNum + 1
      .ID = "E" & Format$(intEmpNum, "00000")
      .Name = txtName.Text
      .Salary = CDbl(txtSalary.Text)
      ' Employee 对象引用添加到集合中,
      ' ID 属性作为键。
      sbMain.Employees.Add empNew, .ID
   End With
   txtName.Text = ""
   txtSalary.Text = ""
   '单击“刷新表”按钮。
   cmdListEmployees.Value = True
End Sub

在 cmdListEmployees_Click 事件过程中的代码,用一个 For Each ... Next 语句将所有的雇员信息添加到 Listbox 控件中。

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

cmdEmployeeDelete_Click 事件用 Collection 对象的 Remove 方法,删除当前 ListBox 控件中选定的集合对象。

Private Sub cmdEmployeeDelete_Click()
   '检查一下,以确保有被选中的雇员。
   If lstEmployees.ListIndex > -1 Then
      '前六个字符是 IDsbMain.Employees.Remove _
      Left(lstEmployees.Text, 6)
   End If
   '单击“刷新表”按钮。
   cmdListEmployees.Value = True
End Sub

将下面的代码添加给“有问题”按钮。

Private Sub cmdTrouble_Click()
   '说些什么!?
   sbMain.Employees.Add Me
End Sub

cmdClose_Click 事件关闭该应用程序。当关闭使用对象的工程时,卸载所有窗体,确保类模块中的所有 Terminate 事件过程都将得到执行。相反,使用 End 语句终止程序显得生硬,不会执行 Terminate 事件。

Private Sub cmdClose_Click()
   Unload Me
End Sub

在示例中,为了添加雇员,可以运行应用程序,在两个文本框中输入值,然后选取“添加”按钮。添加几个雇员,然后用删除和列表按钮来作一下实验。

强健性相当于稻草盖的房子

这种简单的实现方法不是很强健。因为 Employees 属性仅仅是一个公有的 Collection 对象,可能无意中在程序中的任何地方访问它。而且,Collection 对象的 Add 方法不作任何类型检查。例如,在“有问题”按钮的 Click 事件中的代码,会轻率地将对窗体的对象引用插入到雇员集合中。

单击“有问题”按钮,会注意到未出现任何错误。现在,单击“刷新表”按钮。当 For Each ... Next 循环遇到意外的对象类型时,它将导致类型为 13 的错误发生,即“类型不匹配”。

这是用公用的 Collection 对象建立对象模型时,可能会碰到的错误的一个示例。可以从工程的任何地方添加对象,而且对于它们是否将被正确地初始化,没有任何保证。如果程序员复制代码以添加雇员,而且原始代码后来又有所改动,那么要找到产生的错误非常困难。

详细信息   本主题中开始探讨的这个示例,在下面的“私有集合示例:树枝盖的房子”中将继续讨论。