Visual Basic(下简称VB)的模块和过程是指应用程序代码的框架,而建立这样的框架我们必须进行慎密的考虑。目前已经有许多成熟的方法可以用来创建更好的模块和过程,开发工程时,应该使用这些方法。
一、创建具有很强内聚力的模块
过程的重要性往往比模块的重要性更容易理解,过程是指执行一个统一函数的一段代码。但是对于许多开发人员来说,模块的作用比较难于弄清。模块常常被错误地视为是一个仅仅用于存放过程的容器。有些开发人员甚至把这种思路作了进一步的发挥,将他们的所有过程放入单个模块之中。人们之所以不能正确地认识模块的功能,原因之一是模块的实现实际上并不影响程序的执行。当一个工程被编译时,如果所有过程都放在单个模块中或者放在几十个模块中,这没有任何关系。虽然模块的数量对代码的执行并无太大的影响,但是当创建便于调试和维护的代码时,模块的数量有时会带来很大的影响。
模块应该用来将相关的过程组织在一起。在大多数应用程序中,按照某种共性来组织过程是相当容易的。当模块包含一组紧密关联的过程时,该模块可以说具有强大的内聚力。当模块包含许多互不相关的过程时,该模块便具有较弱的内聚力。应该努力创建内聚力比较强的模块。一个非常大的VB工程可能只包含十几个模块,但是这些模块的组织结构应该非常完善。创建模块时,应该知道"模块化"这个术语的含义是什么。模块的基本目的是创建相当独立的程序单元。从根本上来讲,模块可以添加给另一个工程,并且可以通过直接调用它的公用过程来使用它。这种通用模块并不依赖于全局数据或其他模块中的过程。
二、创建松散连接和高度专用的过程
VB能够非常容易地创建过程,但是这种简易性掩盖了创建完美过程需要高度技巧和科学性的问题。VB对过程所作的限制很少,它并不限制放入过程的语句数目,也不限制一个过程能够执行多少个任务。虽然VB并不强制实施这些限制,但是在这些方面我们应该做一些自我控制,这样才能创建更好的过程。
1、使所有过程都执行专门的任务
首先要记住,每个过程都应该执行一项特定的任务,它应该出色地完成这项任务。应该避免创建执行许多不同任务的过程。这常常需要具有一定的远见,因为究竟哪些成分构成一个任务,这并不总是十分明显。创建专用过程有许多好处。首先,调试将变得更加容易。创建专用过程的更重要的好处是可以按计划或者不按计划来修改代码。
2、尽量使过程成为自成一体的独立过程
除了尽量使过程成为专用过程外(这是合乎道理的),还应该尽量使之成为独立的过程。当一个过程依赖于对其他过程的调用时,称为与其他过程紧密连接的过程。紧密连接的过程会使调试和修改变得比较困难,因为它牵涉到更多的因素。当创建的过程依赖于较少的其他过程或者不需要调用其他过程时,那么它就是松散连接的过程。松散连接的过程优于紧密连接的过程,但是我们不可能使每个过程都成为独立的过程。尽管如此,我们应该尽量减少过程之间的连接关系。
三、模块和过程设计的原则
1、为过程和模块赋予表义性强的名字
为了使代码更加容易理解,最容易的方法之一是为我们的过程赋予表义性强的名字。函数名DoIt、GetIt和PrintIt的可读性很难与 CalculateSalesTax、RetrieveUserID和PrintSpreadSheet相比。给过程正确地命名,可使程序工程的调试和维护工作大大改观。我们要认真对待过程命名的工作,不要为了减少键入操作量而降低过程的可理解度。给过程命名时应该大小写字母混合使用,定义过程名时不要使用缩写。这些都是初学者必须要牢记的。下面是一些例子:
不正确:
Private Function InvoicePost()As Boolean
Private Function PrintIt()As Boolean
Public Sub SaveItem()
Public Sub DeleteRecord()
正确:
Private Function PostInvoice()As Boolean
Private Function PrintSpreadsheet()As Boolean
Public Sub SavePicture()
Public Sub DeleteContact()
2、为每个过程赋予明确定义的作用域
作用域是指工程中的变量或过程的可视性。过程可以定义为拥有模块级作用域、全局作用域或友元作用域。当一个过程用Private关键字来说明时,便拥有模块级作用域,并且它只能用同一模块中的过程来调用。如果用关键字Public来说明一个过程,那么这个过程将拥有全局作用域,并且可以用工程中的任何模块来调用。此外,公用类模块的公用过程可用于外部程序。用Friend关键字说明的(公用类模块中的)过程将使该过程成为工程中的所有模块的公用过程,但是它不能使该过程成为外部程序的公用过程。创建过程时,始终都应显式地定义它的作用域。虽然不使用Public Private或Friend将无法定义一个过程,但是我们应该避免这样进行操作。
在许多情况下,我们不用Public、Private或Friend说明的过程实际上将作为模块级(专用)过程来使用。但是,如果不专门说明为专用过程,它们就会无意中创建为公用过程。通过为每个过程赋予一个明确定义的作用域,可以减少代码阅读者需要投入的工作量。另外,应该确保我们为过程赋予最有意义的作用域。如果一个过程只被同一模块中的另一个过程调用,那么请将它创建成专用过程。如果该过程是从多个模块中的多个过程中调用,请将该过程说明为公用过程。每个过程的定义都应该以Public、Private或Friend开头。如果现有的过程不带有这些关键字中的一个,那么我们就必须遍历工程,以便确定每个过程的作用域,并相应地修改其说明。
不正确:
Sub CalculatePOTotals( )
…
End Sub
正确:
Public Sub CalculatePOTotals( )
…
End Sub
3、用参数在过程之间传递数据
虽然模块级变量的问题不像全局变量那么多,但是我们也应该尽量避免使用模块级变量。一般来说,变量的作用域越小越好。为了减少模块级变量和全局变量,方法之一是将数据作为参数在不同过程之间传递,而不是让过程共享全局变量或模块级变量。
例如为每个参数指定数据类型。这个问题应该给予充分的重视。创建带有参数的过程时,请务必将每个参数明确说明为一个特定的数据类型。当我们省略参数说明中的As部分时,该参数将作为Variant(变码)来创建。如果我们想创建Variant参数,请使用As Variant进行显式创建。
不正确:
Private Sub CreateStockRecord(ItemID, Repair, Quantity)
正确:
Private Sub CreateStockRecord(strItemID As String, blnRepair _
As Boolean, sngQuantity As Single)
4、使用统一和直观明了的方式来调用过程
VB提供了许多快捷操作方式,可供在编写代码时使用。一般来说,这些快捷方式不影响代码的运行性能,但是它们往往牺牲了代码的可读性,以便在进行软件开发时省去一些击键操作。应该尽量使代码做到直观明了。有的时候,也就是当调用过程的时候,可以采用快捷方式,然而我们不应该这样去做。
我们可以用许多不同的方法来调用一个过程。当调用Sub过程时,可以使用单词Call,也可以省去这个单词。例如,下面这两个语句均调用相同的Sub过程:
CallShowError("clsApplication","ShowRep",Err.Number,Err.Description)
ShowError"clsApplication","ShowRep",Err.Number,Err.Description
虽然可以省略单词Call,这样我们就不必键入两个括号来启动代码,但是我们应该避免使用这种方法。关键字Call专门用来指明该语句是调用一个Sub过程,而不是调用Function过程,因此它使代码更容易阅读。
VB允许我们以完全相同的方法来调用Sub过程和Function过程。请看下面这个函数:
Public Function DisplayContact(lngContactNumber As Long) As Boolean
…
End Function
我们可以使用下面的任何一个语句来调用该函数:
Call ShowRep(lngRepNumber)
ShowRep lngRepNumber
blnResult=ShowRep(lngRepNumber)
为了使代码尽可能直观明了,必须将调用Sub过程与调用Function过程区分开来。调用Sub过程时,始终都应使用关键字Call;调用Function过程时,始终都应检索Function调用的值,即使我们并不使用这个值,也应这么做。