VBScript中的类

1 VBScript 中的类

1.1 对象、类和组件

  • 对象是复杂数据和程序结构在内存中的表现,只有在程序运行时才存在
  • 对象与数组还是有些区别,最重要的就是对象并不只是像数组那样存放一些复杂数据(以属性的形式);对象还有“行为”(也就是说“它知道该怎么做”)这表现为方法。属性可以存放任何类型的数据,而方法则可以是过程或函数。将数据和行为一起放入对象中,这样就可以在设计程序时将被操作的数据和操作数据的代码放在一起
  • 类是对象的模板。对象只有在运行时才会存在于内存中,而类则是在设计时就能直接使用的程序设计结构。类是代码,而对象是在程序运行时对这段代码的使用。如果要在运行时使用对象,必须先在设计时定义一个类。在运行时会根据类所提供的模板创建对象。例如,可以编写一个名为 Customer 的类。保存这个类定义之后,就可以再用其他代码在内存中创建任意数量的 Customer 对象。

1.2 类语句

  • 创建 VBScript 类的关键字是 Class 语句。跟用Function … End Function 或 Sub … End Sub 语句设定过程的边界类似, Class 和 End Class 语句也适用于设定类的边界。可以在一个脚本中使用多个Class … End Class 代码块定义多个类(但是在 VBScript 中类不能嵌套)。
  • 通常,您必须将定义 VBScript 类的代码与创建类实例的代码放在一起。这看上去是一个很大的限制(因为创建类的一个目的就是方便代码的移植和重用)但是这里有另外两种实现这个目的的方法。
  • 除了是否在同一个脚本文件中的区别, Visual Basic 程序员可以毫无障碍地适应 VBScript 类的使用。除了 Visual Basic 和 VBScript 两者在语言上的差别, VBScript 类的结构和相关技术与 Visual Basic 都是一样的。

下面是 Class 的基本语法。

Class MyClass
< rest of the class code will go here >
End Class

当然,应该用自己所定义的类的名称替换其中的 MyClass。这个类的名称以及相同作用域中用 INCLUDE 指示符包含进来的类名称,在脚本中都应该是独一无二的。类名称还不能与 VBScript 的保留字(比如 Function 或 While)重复

1.3 定义属性

在脚本根据类创建对象时,属性是存储和访问数据的机制。通过属性,数据可以存放在对象中;也可以通过属性从对象中获取数据

1.3.1 私有属性变量

  • 存储属性的值的最好方式就是私有属性变量。
  • 这是定义为类级作用域的变量(在类的开头)。这个变量是私有的(也就是说不能直接从类的外部访问这个变量),存放有属性的值。使用类的代码通过· Property Let、 Set 和 Get· 过程与其进行交互,但是这些过程只是这个私有属性变量的门户而已。

可以这样定义一个私有属性变量:Class Customer

Private mstrName
< rest of the class code will go here >
End Class

1.3.2 Property Let

Property Let过程是一种特殊的过程,用于在类的外部给私用属性变量赋值。 Property Let 过程类似于 VBScript 中没有返回值的子过程。下面是它的语法。

Class Customer
Private mstrName
Public Property Let CustomerName(strName)
mstrName = strName
End Property
End Class
  • 这里没有使用 Sub 或 Function语句来定义这个过程,而是使用的Property LetProperty Let 过程必须接收至少一个参数。没有这个参数就无法实现 Property Let 过程的目的,也就是使得外部代码可以将值存放到私有属性变量中。
  • 这里要注意属性过程中的代码是如何将传递给该过程的 strName 值保存到 mstrName私有属性变量中的。这个过程中可以没有任何代码,这也就不会将传递过来的值存放到某个变量或对象中,但是这完全不符合 Property Let 过程的目的。
  • 也可以随意地往这个过程中添加代码。在某些情况下,可能要在将传递过来的值真正赋给私有属性变量之前先对其做一些检查。例如,如果客户姓名的长度不能超过 50 个字符,就需要检查 strName 参数是否超过了 50 个字符的长度;如果超过了这个长度,就用Err.Raise()方法将这个错误告诉调用代码。
  • 最后,属性过程必须以 End Property 语句结束(就像 Function 过程必须以 End Function结束,Sub 过程必须以 End Sub结束一样)。如果要跳出属性过程,可以使用 Exit Property语句(跟用 Exit Function跳出 Function,用 Exit Sub 跳出 Sub 一样)。

1.3.3 Property Get

Property Get 过程跟Property Let过程正好相反。Property Let过程是用于在类外部的代码中给私有属性变量赋值,而 Property Get过程则是允许类外部的代码读取私有属性变量的值。Property Get过程跟 VBScript 的 Function 过程类似,都有返回值。这里是它的语法。

Class Customer
Private mstrName
Public Property Let CustomerName(strName)
mstrName = strName
End Property
Public Property Get CustomerName()
CustomerName = mstrName
End Property
End Class
  • VBScriptFunction 过程类似, Property Get 过程会给调用它的代码返回一个值。这个值通常是私有属性变量的值。注意 Property Get 过程的名称与相应的 Property Let过程的名称是一样的。Property Let 过程将值存放到私有属性变量中,而 Property Get 过程则将其读取出来。
  • Property Get 过程不需要任何参数。 VBScript 允许加入参数,但是如果要这么做,就必须给这个属性的 Property Let 或 Property Set 过程(如果使用了这个)也添加一个额外的参数。因为 Property Let/Set 过程的参数必须比相应的 Property Get 过程的参数多一个。给Property Let/Set过程添加一个额外的参数是很难看的,并且要求使用这个类的代码在 Property Let 过程中使用多于一个参数也是很不好的形式。如果觉得某个 Property Get 过程确实需要一个参数,那最好是添加一个额外的属性来实现这个 Property Get 参数的功能。如果 Property Get 过程返回的是一个指向对象变量的引用,就可能需要用 Set语句返回这个值。例如:
Class FileHelper
' Private FileSystemObject object
Private mobjFSO
Public Property Get FSO()
Set FSO = mobjFSO
End Property
End Class

1.3.4 Property Set

  • Property Set 过程与 Property Let过程很类似,但是 Property Set 过程是针对基于对象的属性。当需要在属性中存放对象(而不是数字、日期、布尔或字符串子类型的变量),就可以提供一个Property Set过程取代 Property Let过程。下面是一个 Property Set 过程的语法。
Class FileHelper
' Private FileSystemObject object
Private mobjFSO
Public Property Set FSO(objFSO)
Set mobjFSO = objFSO
End Property
End Class

从功能上来说,Property LetProperty Set过程的功能是一样的。但是 Property Set过程有两个不同之处:

  • 明确地说明这个属性是一个基于对象的属性(任何使得代码意义更明确的技术都比其他功能相同的技术更受偏爱)。
  • 类外部的代码必须用 Set Object.Property = Object才能写入这个属性(因为这是实现该功能的典型方法,所以这也是优点)。

例如,下面的代码根据前面介绍的类创建了对象。

Dim objFileHelper
Dim objFSO
Set objFSO = _WScript.CreateObject("Scripting.FileSystemObject")
Set objFileHelper = New FileHelper
Set objFileHelper.FSO = objFSO

注意最后一行代码在给 FSO 属性赋值时使用了 Set 语句。这是必须的,因为 FileHelper类是用Property Set过程给 FSO属性赋值的。如果没有最后一行开头的 Set 语句, VBScript就会报错。若类中的属性是基于对象的,通常就应该用 Property Set 过程。大部分使用类的程序员也都希望如此。

1.3.5 创建只读属性

有两种方法可以创建类的只读属性:

  • 只为这个属性提供 Property Get 过程。
  • Property Get过程声明为公共的,而将 Property Let 过程声明为私有的。

1.3.6 创建只写属性

有两种方法可以创建只写属性,这两种方法与创建只读属性的方法完全相反:

  • 忽略 Property Get 过程,只提供 Property Let 过程。
  • 用 Public 语句声明 Property Let 过程,用 Private 语句声明 Property Get 过程

1.4 定义方法

方法(method)实际上就是函数和过程的另一个名称
方法的语法跟定义 VBScript 函数和过程的语法是一样的。唯一需要额外考虑的就是应该声明为公共的还是私有的

Class Greeting
Private mstrName
Public Property Let Name(strName)
mstrName = strName
End Property
Public Sub ShowGreeting(strType)
MsgBox MakeGreeting(strType) & mstrName & "."
End Sub
Private Function MakeGreeting(strType)
Select Case strType
Case "Formal"
MakeGreeting = "Greetings, "
Case "Informal"
MakeGreeting = "Hello there, "
Case "Casual"
MakeGreeting = "Hey, "
End Select
End Function
End Class

类外部的代码可以调用 ShowGreeting()方法,这是公共的;但是不能调用 MakeGreeting()方法,因为这是私有的,只能在内部使用。 示例脚本开头的代码使用了这个类

Dim objGreet
Set objGreet = New Greeting
With objGreet
.Name = "Dan".ShowGreeting "Informal"
.ShowGreeting "Formal"
.ShowGreeting "Casual"
End With
Set objGreet = Nothing

1.5 类事件

  • 事件(event)是一种会自动被调用的特殊方法。在任何特定的环境中,所使用的类都支持一个或若干个事件。当给定的环境中支持某个事件时,您可以编写一个事件处理器(eventhandler),这实际上就是在事件发生时会自动调用的特殊方法
  • 任何 VBScript 类都自动地支持两个事件:Class_InitializeClass_Terminate

1.5.1 Class_Initialize 事件

当有代码根据类实例化出一个对象时就会引发类中的Class_Initialize 事件。只要是基于某个类实例化出一个对象,就会发生这个事件,但是类中是否含有对此做出响应的代码就取决于自己了。如果不想响应这个事件,完全可以忽略这个事件的事件处理器。下面这个例子中的类含有一个 Class_Initialize 事件处理器。

Class FileHelper
' Private FileSystemObject object
Private mobjFSO
Private Sub Class_Initialize
Set mobjFSO = _
WScript.CreateObject("Scripting.FileSystemObject")
End Sub
'<<rest of the class goes here>>
End Class
  • 从技术上来说,您可以用 Public 语句(而不用 Private)声明事件处理器,但是事件处理器通常都是私有的。如果将其声明为公共的,类外部的代码就可以像调用其他方法一样调用它,这通常都不是我们所希望的。
  • 在一个类中只能有一个 Class_Initialize 事件处理器。如果不需要的话也可以一个都没有,但绝对不能多于一个。

1.5.2 Class_Terminate 事件

Class_Terminate 事件与 Class_Initialize 事件相反。当类被实例化为对象时会触发 Class_Initialize 事件,而当基于这个类的对象被销毁时则会触发 Class_Terminate 事件。有两种销毁对象的方法:

  • 将特殊值 Nothing 赋给最后一个引用了该对象的对象变量
  • 超出了最后一个引用该对象的对象变量的作用域

发生这两种情况中的任一种时, Class_Terminate 事件会在对象真正被销毁之前发生。
下面是前一节例子中见过的 FileHelper类,现在添加了一个 Class_Terminate 事件处理器。

Class FileHelper
' Private FileSystemObject object
Private mobjFSO
Private Sub Class_Initialize
Set mobjFSO = _
WScript.CreateObject("Scripting.FileSystemObject")
End Sub
Private Sub Class_Terminate
Set mobjFSO = Nothing
End Sub
'<rest of the class goes here>
End Class

在这个例子中,用 Class_Terminate 事件处理器销毁了在 Class_Initialize 事件中实例化的对象。这实际上是没有必要的,因为当 FileHelper 对象被销毁时,私有的 mobjFSO 变量也会超出其作用域,脚本引擎会自动地将其销毁。但是,有些程序员喜欢显式地销毁所有实例化的对象,这对于示例还是很有用的。
还可以用 Class_Terminate 事件关闭数据库连接、关闭文件或是将类的某些信息保存到数据库或文件中。关于 Class_Initialize 事件处理器的语法限制同样也适用于 Class_Terminate事件处理器

1.6 构建和使用 VBScript 类

CreateObject()函数只是用于实例化非原生VBScript对象(比如 DictionaryFileSystemObject),而必须用 New 来实例化同一个脚本中自定义的VBScript 类。背后的原因很复杂,所以只需要记住这条原则:
如果用自定义的 VBScript 类实例化一个对象,使用 New;否则,用 CreateObject
但是也有特例,正则对象RegExp就必须用new

发布了334 篇原创文章 · 获赞 186 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/u012060033/article/details/103433880