前言
首先,在我进入实质性主题并解释如何建立类之前,我希望保证你知道“对象”。虽然你可以在程序中使用对象而不用知道其正确的规则,但我并不建议如此!对于对象的初学者,接下来的部分将让你了解其概念及内容。已经了解面向对象编程(OOP)的读者可以跳过这章节。
导论
“对象是什么?”——对象通常代表某种实体,主要是一个变量和函数的集合。
“实体是什么?”——字面上说,实体是一个“事物”,我的意思是一个概念或者任何一个物体。例如,一辆汽车是一个实体,因为它是一个物体。你公司销售部门销售产品也是一个实体,当然,你也可以将其拆开来看,销售人员、客户、产品等都是实体。
让我们更深入的来看“销售”这个实体(对象)。为了使你更准确地有一个销售的“映像”,你需要知道客户买了什么,是哪个客户,谁是销售人员等等……这看来是一个简单的事件,但假设所有信息是存储在单独的数据库表中的,那么当你需要获得某个销售过程所有相关信息时,你必须在你的数据库中做多次独立查询,再将所有的数据集拢。有没有更简便的办法而一次获得销售的所有信息呢?“对象”。
在对象中,你可以植入代码以从其他表中获得数据,你也可以保存对象属性的所有信息,这样,你可以轻松地使用代码管理你的销售数据。例如:
'Open the database connection
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open "MyDSN"
'Create the recordset object
Set objRS = Server.CreateObject("ADODB.Recordset")
'Define the SQL query
strComplexSQLQuery = "SELECT C.Name, S.Name FROM Customers C, " & _
"Salespeople S, Sales Sl WHERE Sl.CustomerID=C.ID AND " & _
"Sl.SalespersonID=S.ID AND Sl.ID=" & strIDOfThisSale & ";"
'Open the recordset
objRS.Open strComplexSQLQuery, objConn, adOpenForwardOnly, _
adLockReadOnly, adCmdText
'Take the customer and sales person names from the recordset
strCustomerName = objRS(0)
strSalesPersonName = objRS(1)
'Tidy up the objects
objRS.Close
objConn.Close
Set objRS = Nothing
Set objConn = Nothing
'Output the data
Response.Write "This sale was made by " & strSalesPersonName & _
" to " & strCustomerName
可以使用“对象”来替代:
'Create the "Sale" object
Set objSale = New Sale
'Lookup the correct sale
objSale.ID = strIDOfThisSale
'Output the data
Response.Write "This sale was made by " & objSale.SalesPersonName & _
" to " & objSale.CustomerName
'Tidy up the objects
objSale.Close
Set objSale = Nothing
如果你使用“Sale”对象做比打印更多的事,可以让你省去很多的打字时间。
计算中,对象包括“属性”和“方法”。属性主要是储存在对象中的一个变量,其用法与变量相同。唯一的区别在于参数赋值为:strMyVar = "This is a string variant", 而对象属性为 objObject.Property="This is a string variant"。这点非常简单而有用处。方法可以理解为植入对象中的函数与过程,可以使用strMyVar = objObject.MethodName(strMyVar)来代替strMyVar =FunctionName(strMyVar)。写法不同,但功能相同。属性的一个例子是对象Response中的ExpireAbsolute,Response.ExpiresAbsolute = CDate("1 September 1999")。方法的一个例子是对象Response中的Write方法,Response.Write "Hello world!"。
VBScript的一个新特性就是其可以创建新的对象而不需要求诸于花销时间都极大的编译器。我将向读者展示如何创建对象的类,并希望提供一个良好的开端。
在VBScript中使用类(二)
创建对象
在VBScript中创建对象类型(类)时,你首先要知道,这真的很容易!我在一个下午自学,只是阅读了Microsof VB Script 的参考书,但必须承认,这书不是最容易阅读的文档。
初学者需要安装VBScript 5.0引擎,可以在Microsoft's Scripting Site下载。
我们来看代码。类的定义与函数和子过程非常类似。起始行为Class <MyClassName>,结尾是End Class,所有的对象定义写在中间部门。现在我们可以用所学的来建立第一个类,不实现任何功能的类。
Class 4GuysTestObject
'你的ASP代码
End Class
这看上去不是那么回事,但当你写入下面的代码后,你将创建一个对象的实例:
Dim objTestObject
Set objTestObject = New 4GuysTestObject
Set objTestObject = Nothing
显然,我们现在还不能用对象做任何事,现在我将解释如何在对象中定义属性和方法。
使用对象可以做的最基础的,是建立一组数据。例如,假如要将时间、日期及视频程序标题建立在一起,你可以创建一个包含属性“StartTime”, “ProgramDate”和“ProgramTitle”的对象。代码如下:
Class TVProgram
Public StartTime
Public ProgramDate
Public ProgramTitle
End Class
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.ProgramDate = DateSerial(1999,9,17)
objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _
objTVShow.StartTime & " on " & objTVShow.ProgramDate
代码工作的方式是,我们定义StartTime,ProgramDate和ProgramTitle为类TVProgram的属性。这样,这些属性就像其他变量一样来处理,没有设置值则不会执行代码。属性名字前的Public字段有其真实含义,而且非常重要。如果你不特指一个方法或属性为public或private,系统默认值为public,但最好养成定义任何值的良好书写习惯(也方便你之后自己的阅读)。
上面程序的结果大致如下(决定于你的本地服务器配置):
The Jerry Springer Show is on at 5:30pm on 17/09/99.
我在英国,所以日期现实如上。不论你跑什么工程,它的效果都不错,但只有你开始使用其他对象的功能,为你可能需要的所有信息和功能,创建一个完美的接口,以支持你所建对象包围的实体,你才会体会到对象的真正实力。
现在,如果你不喜欢上面例子显示日期的方法,而希望以同一种格式现实日期,也没有不要在引用每个ProgramDate属性时加FormatDateTime(),你只需要将此类代码植入属性本身。
这样需要用另一种方法定义属性。同样,我们将使用ProgramDate为外部可见属性,但因为ProgramDate属性将成为一个函数而不是静态值,我们将实际日期保存在另一个属性中internal_ProgramDate。
Class TVProgram
Public StartTime
Public internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & _
" " & MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public ProgramTitle
End Class
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.internal_ProgramDate = DateSerial(1999,9,17)
objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _
objTVShow.StartTime & " on " & objTVShow.ProgramDate & "."
程序的结果如下:
The Jerry Springer Show is on at 5:30pm on 17 September 1999.
在VBScript中使用类(三)
我们来分析一下(2)中的程序:
Class TVProgram
Public StartTime
Public internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & _
" " & MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public ProgramTitle
End Class
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.internal_ProgramDate = DateSerial(1999,9,17)
objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _
objTVShow.StartTime & " on " & objTVShow.ProgramDate & "."
当调用对象的属性ProgramDate时,实际上执行了函数ProgramDate,即如上定义的函数,而很快你也将习惯这种在声明部分使用Public或Private关键字的方式。关键字“Property”,告知了编译器如同调用属性一样在外部调用函数。接着的“Get”,表明该函数是输出还是获得一个值。
Get的意思是“允许外部代码去‘获取’一个值”,与其类似的关键字还有“Let”和“Set”,但这两个比较复杂,因而我们以后再讨论。
接下去的代码看来有点难度的,给objectname.internal_ProgramDate赋值并通过objectname.ProgramDate来调用它。如果可以使用相同关键字同时为其赋值并获得它的值不是更好吗?当然,那也可以。
如果定义Get和Let属性的名称相同,可以将它们当作对象相同的属性,但这只限于它们定义了相同数量的成员。(以下代码看来不太相同,仅作为实例参考)
Class TVProgram
Public StartTime
Public internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & " " _
& MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
internal_ProgramDate = CDate(varDateIn)
End Property
Public ProgramTitle
End Class
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.ProgramDate = "17 Sept 99"
objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _
objTVShow.StartTime & " on " & objTVShow.ProgramDate & "."
以上代码中Let的声明部分看来似乎是一个多余的元素,当我第一次看到时研究了很长时间。每次我使用“0”作为变量用在每个属性上,我总是得到这个错误信息,“元素数量必须相等”。“它们确实相等!”抓狂之后,我回过头去看程序才觉得自己的愚蠢!:)
原因是,当你试图为ProgramDate赋值时,你会使用这样一行程序:
objTVShow.ProgramDate = dtmMyDate
为了方便,等号右边的值(这里指dtmMyDate)作为了一个程元赋给了函数。因此编译器可能会认为在Get ProgramDate行有0程元,而Let ProgramDate却多一个!分配的值总是被略过而作为属性的最后一个程元,所以即使你使用其他程元,所赋的值总是作为最后一个程元。
现在看程序。无论通过ProgramDate设置日期为文本形式,还是用internal_ProgramDate译成日期变量,程序都没有问题。但能不能只使用一个入口呢?
如果internal_ProgramDate只能在内部有效,而使用Let ProgramDate检查传输的数据类型,我们就可以作出选择。例如:
Class TVProgram
Public StartTime
Private internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & " " & _
MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
If IsDate(varDateIn) Then
internal_ProgramDate = varDateIn
Else
'Place some error handling code in here.
End If
End Property
Public ProgramTitle
End Class
并同样声明StartTime属性:
Class TVProgram
Private internal_StartTime
Public Property Get StartTime
StartTime = Hour(internal_StartTime) & ":" _
& Minute(internal_StartTime)
End Property
Public Property Let StartTime(ByVal varTimeIn)
If IsDate(varTimeIn) Then
internal_StartTime = varTimeIn
End If
End Property
Private internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & " " _
& MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
If IsDate(varDateIn) Then
internal_ProgramDate = varDateIn
End If
End Property
Public ProgramTitle
End Class
...
现在的代码离我们想要的还是有些不太实用,我们将在其他页使用类TVProgram,因此最好将其独立定义,以便所有也面都可以调用。我们将在第四部分讨论这点。
在VBScript中使用类(四)
现在的代码离我们想要的还是有些不太实用,我们将在其他页使用类TVProgram,因此最好将其独立定义,以便所有也面都可以调用。创建一个ASP页面,并命名为TVProgramClass.asp,我们在其中定义类TVProgram。
--TVProgramClass.asp--
<%
Class TVProgram
Private internal_StartTime
Public Property Get StartTime
StartTime = Hour(internal_StartTime) & _
":" & Minute(internal_StartTime)
End Property
Public Property Let StartTime(ByVal varTimeIn)
If IsDate(varTimeIn) Then
internal_StartTime = varTimeIn
End If
End Property
Private internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & _
" " & MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
If IsDate(varDateIn) Then
internal_ProgramDate = varDateIn
End If
End Property
Public ProgramTitle
End Class
%>
这样就可以在任何ASP中调用我们定义的类了,语法如下:
<!-- #include virtual="TVProgramClass.asp" -->
<%
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.ProgramDate = DateSerial(1999,9,17)
objTVShow.ProgramTitle = "The Jerry Springer Show"
%>
<%= objTVShow.ProgramTitle %> is on at <%= objTVShow.StartTime %> on <%= objTVShow.ProgramDate %>.
这里有一个建议。如果你重命名你的包含文件.asp,并保证所有重要代码都在<CODE><% ... %>< CODE>中,那么就算有人猜到了你包含文件的文件名,也没办法看见里面的内容!
评论:
VBScript类在封装的层面上,还是有不少好处的,增加了代码的可读性与可维护性以及清晰度,但是,没有继承和重载等特性,并不是真正意义上的OOP。没有集合,但是据说可以用Scripting.Dictionary,据说更好用、更快。不过,感觉总是鸡类(肋)。