微型机与应用
MICROCOMPUTER & ITS APPLICATIONS
2000　No.19　No.1　P.12-14




Visual Basic中过程间数据共享方法
许中卫戴宗友
摘 要： 在事件驱动程序编程环境下，Visual Basic过程间共享数据及过程间共享代码的一组方法，并相应讨论这些方法对软件复用性和可维护性的影响。
关键词： Visual Basic 事件驱动程程序设计 变量 可维护性 复用性
　　具有面向过程方式编程经验的软件开发人员，在使用Visual Basic等可视化开发工具时，其开发工作大多数是以E－DP（事件驱动程序设计方式展开的。在E－DP中，用“过程（Procedure）”来标识1组相关代码组成的子程序、过程/函数，而不用“模块”，这是因为在E－DP中，“模块”通常指1个容器（Container）；Visual Basic中有3类模块：1．Form（窗口――所包含的典型内容有可视目标（Visual Objects）、过程（Procedures）及说明（declaration）等；2．标准/代码模块（Standard/CodeModule――通用过程和说明的容器；3．类模块（Class Module――各种类定义的容器。下面介绍在E－DP编程环境下，Visual Basic过程间共享数据的方法以及过程间共享代码的方法，并相应讨论对复用性和可维护性的影响。
1 关于全局变量
　　在面向过程程序设计方法中，由于全局变量的值能被系统中的任何过程修改，所以全局变量被认为是损害过程独立性的重要因素之一，所以在面向过程程序设计中，一个重要的原则是：尽量避免使用全局变量，而提倡使用参数显式地传给被调用的过程。同样，在E－DP编程环境下使用全局变量，对于变量这一因素来说，将最大限度降低程序的可维护性和过程的复用性。因此在使用VB时，也应尽量避免使用全局变量。
2 使用Form级私有变量
　　在面向过程程序中，主要有全局变量和局部变量。前者在1个应用中整个范围内有效，后者则局限在1个应用的某一过程中有效；VB中，除了上述2种变量外，还有模块级私有变量，其作用域为说明该变量的模块。对于VB中的3种模块（Form、标准/代码模块和类模块），这里侧重讨论与Form相关的模块级变量。
　　图1列出了2个事件过程，事件过程cmdStartClick（）是用鼠标点触命令按钮cmdStart事件的处理程序。表示1个事务活动的开始。事件过程cmdStopClick（）是用鼠标点触命令按钮cmdStop事件的处理程序，表示1个事务活动的结束。用鼠标点触命令按钮cmdStart的时间存放在变量mStartTime中，在事件过程cmdStopClick（）中要利用StartTime计算由按钮cmdStart启动的事务活动所用的时间；然而没有办法将mStartTime的值通过参数传递给事件过程cmdStopClick（）（因为事件过程的参数是由系统固定的），因此，在这个应用中，说明了Form级私有变量mStartTime，使得这个容器中的所有过程都可以直接引用或修改mStartTime。

图1　同一Form中的事件过程间数据传送
　　由于Form级私有变量只在说明它的模块中可用（1个Form、标准模块或类模块），所以对可维护性的影响要小一些（相对于全局变量），同时也解决了图1所示的应用中事件过程间数据传送问题。
3 在通用过程中的模块级私有变量
　　图2是在图1所示的例子基础上的1个改进版本，在图2所示的例子中，事件过程cmdStart_Click（），调用通用过程procStart来读取开始时间；相似地，事件过程cmdStop_Click（），调用通用过程procStop来计算事务耗时，计算出的结果通过参数传给cmdStop_Click（）；在本例中为了例示在通用过程中，使用模块级私有变量对复用性的影响，在图中所列的2个通用过程中，都直接使用模块级私有变量mStartTime，而不使用参数将其由事件过程传给相对应的通用过程。

图2　在通用过程中使用From级私有变量
　　由于通用过程procStart和procStop使用了模块级私有变量mStartTime，如同前面讨论的一样，这增加了对procStart和procStop的理解难度。另外，由于使用了mStartTime而降低了procStart和procStop的复用性。
　　对图2所示的通用过程procStart和procStop进行改进，即在其中不直接使用模块级私有变量，而是通过参数传递mStartTime的值，这种改进的版本如图3所示。

图3　在通用过程中使用参数传送数据
　　相对图2所示的版本而言，通用过程procStart和procStop的复用性以及程序的可维护性都得到了提高。这时，如果用户接口有所变动（会导致原事件过程名的改变等），各调用过程不用作任何修改，因为这时调用过程调用的已不是事件过程本身，而是事件过程所调用的通用过程。例如，本来如果鼠标点触按钮时计算事务耗时，改为在某一文本编辑框内按下回车键时计算事务耗时。由于计算事务耗时的程序代码已分离成一通用过程procStop，所以，当用户接口作上述变动后，所用调用procStop的过程无须作任何修改。
　　如果通用过程procStart和procStop，在容纳它们的Form中，将其设置为共用过程，则可由其它Form中的过程调用。由于Form既是容器也是用户接口，所以当界面修改涉及到删除包含procStart和procStop的Form时，所有其它Form中调用procStart和procStop的过程，都要作相应的修改；进一步，其中含有共用通用过程的Form在程序运行过程时，内存中始终需要该Form的副本（即从用户界面而言已不需要该Form，但其中含有供其它Form调用的通用过程，所以仍不能关闭/释放该Form），因此，为了提高可维护性和运行效率，共用通用过程应保存在标准/代码模块中，而不是存放在Form中。
　　因此，即使是象mStartTime一样的模块级全局变量，也应尽量避免在通用过程中使用，它们应作为参数由事件过程显式地传给通用过程，而不是直接在通用过程中使用全局变量。
4 使用Form级公用变量
　　在以上的例子中，由于2个事件过程在同一Form中，所以变量mStartTime说明为Form级私有变量。现在考虑另一种情形：cmdStart在Form1中，而cmdStop在Form2中，一种方法是将Form1中的变量mStartTime说明为Form级的公用变量，在Form2中便可以加前缀引用，如图4所示。从而将开始时间从Form1中的事件过程cmdStart_Click（）传给Form2中的事件过程cmdStop_Click（）。但在二事件过程（cmdStart_Click（）/cmdStorp_Click（））与其对应的通用过程（procStart/procStop（））间仍以参数的形式传递“开始时间”，防止在通用过程中直接使用Form级公用变量。

图4　在Form间使用Form级公用变量传送数据
　　Form级公用变量，不仅在说明它的模块中可用，只要以说明该变量的Form名称为前缀，其它模块中的过程也可以直接修改引用，所以，相对Form级私有变量而言，它在更大的程度上损害可维护性和可复用性。
　　有一种情况，如上述示例，在1个Form中说明的全局变量，在其它Form中不对其修改；为了消除公用变量的副面作用，可用1个Form级私有变量及1个公用通用过程替代，即将该变量说明为From级私有变量，同时增加1个公用过程用以读取该变量；如图5所示。将Form1中的全局变量说明为Form级私有变量，增加全局通用过程getStartTime，在Form2中可以调用过程getStartTime读取mStartTime的值，这样就防止了在Form1以外的过程修改mStartTime的值。

图5　在From间使用公用通用过程传送数据
　　在不同Form中的事件过程间，避免使用Form级全程变量共享数据的另一种方法是：使用一个模块级私有变量和标准/代码模块中的一个全局通用过程。如图6所示。标准/代码模块ProjMd中说明模块级私有变量mStartTime，其中的过程procStart和过程procStop通过mStartTime共享事务开始时间，由于procStart和procStop说明为公用通用过程，所以Form1和Form2中的事件过程可调用。模块级私变量可用范围是标准/代码模块ProjMd，它在相应工程（Project）的整个运行期间有效。当用鼠标点触命令Form1中按钮cmdStart时，唤醒事件过程cmdStart＿Click（），cmdStart＿Click（）调用ProjMd中的procStart将事务开始时间保存在变量mStartTime中；当用鼠标点触命令Form2中按钮cmdStop时，唤醒事件过程cmdStop＿Click（），cmdStop＿Click（）调用ProjMd中的ProcStop，ProcStop利用mStartTime计算事务耗时elasedTime。图6没有使用Form级全局变量，然而，在其中使用了全局通用过程ProcStart和ProcStop，在任何Form中都可以调用ProcStart修改mStartTime，但只能通过调用ProcStart来进行，可避免对全局变量的“无意”修改。

图6　在Form间利用标准/代码模块传送数据
5 总 结
　　一般事件过程的复用性都很低，将事件过程中用以共享的一组代码分离成1个通用过程，可用这种间接的方式增加原事件过程的复用性和可维护性，如果一个通用过程由多个模块共享，则该通过过程应该放在标准/代码模块中，而不是放在Form中。
  本来，在过程间传送数据应利用过程的参数来实现，然而，没有办法通过参数将数据从一个事件过程传送到另一个事件过程，较好的办法是使用Form级的私有变量，应尽量避免使用全局变量及Form级共用变量；如果1个变量只在1个Form中修改，而在其它Form中是只读性引用，则可使用1个Form级私有变量和1个全局过程来替代使用全局变量或以Form名称为前缀的Form级共用变量。
　尽管使用Form级私有变量实现事件过程间数据传送，但在通用过程中仍要避免直接使用，应使用过程参数将Form/模块级私有变量、Form级公用变量、或全局变量的值传给通用过程，这样可以提高过程的复用性和可维护性。
许中卫（安徽大学计算机系230039）
戴宗友（中国人民解放军炮兵学院230031）
参考文献
1，Bard D著，赵军，李杜译．FOXPRO事件驱动程序设计．北 京：清华大学出版社，1994
2，冯玉林，赵宝华．软件工程．中国科学技术大学出版社， 1986
3，刘炳文．Visual Basic 4．0程序设计基础．北京：人民邮电 出版社，1998
收稿日期：1999－07－16
