VFP中三种模块化程序设计方法的研究与实践

来源 :计算机时代 | 被引量 : 0次 | 上传用户:collinccs
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘 要: VFP是基于数据库管理和应用程序开发的高级语言。VFP中可以用子程序、过程、函数三种方式实现模块程序设计。这三种方式功能相同,但格式、调用方式、数据传递方式又不尽相同;这三种方式可以相互转换。学生在学习中常常不能确认应该采用哪种方式实现模块功能。为此,详细分析了三种方式的设计过程,以帮助学生理解并掌握这三种方式的结构及其转换格式,各种不同格式的调用方式,以及它们的用处和模块的编程方法。
  关键词: 子程序; 过程; 函数; 局部变量
  中图分类号:TP392 文献标志码:B 文章编号:1006-8228(2012)11-44-04
  Research and practice of three modularized program design methods in Visual FoxPro
  Wang Xiujuan1, Hong Jun2
  (1. School of electronics and computer science and technology, North University of China, Taiyuan, Shanxi 030051;
  2. School of Software, North University of China)
  Abstract: Visual FoxPro is an advanced language which is based on database management and application program development. There are three kinds of modularized programming method including subprogram, procedure and function. Though they have the same function, they are different in format program invocation, data transmission and can be transformed to each other which make the students unclear about which method they should use to design the module. A detailed analysis of the three methods and some examples are given to help the students to learn the structure, transition and invocation of the three methods and master the modularized program design easily.
  Key words: subprogram; procedure; function; local variable
  0 引言
  VFP(Visual FoxPro)是一种关系型数据库管理系统,它不仅支持面向对象的可视化程序设计,还支持传统的面向过程的程序设计。面向过程的程序设计方法要求将一个大的系统分解为多个模块,用以实现功能的分解和代码的重用。VFP中实现模块的程序设计方法比较多,包括:子程序、过程、函数。下面举例分析三种方式的异同。
  1 三种设计方法详解
  1.1 子程序
  在VFP中子程序的结构和程序的结构基本相同,通常使用MODIFY COMMAND命令单独建立一个程序文件,以扩展名.PRG保存成一个程序文件[1]。一般习惯在子程序的末尾加上RETURN命令返回调用处。调用子程序的格式为:DO 子程序文件名[WITH <参数表>]。
  1.2 过程
  VFP中按照过程是否单独保存成程序文件将过程分为两种:内部过程和外部过程。内部过程与主程序放在一个文件里,通常放在主程序文件的后面;外部过程单独保存成一个程序文件,优点是不依附于主程序,可以被多个程序共享[2]。
  内部过程格式:
  PROCEDURE <过程名>
  [PARAMETERS <形式参数表>]
  <命令组>
  RETURN|ENDPRO
  调用格式:DO 过程名 WITH <参数表>
  下面举例说明内部过程和外部过程之间的区别,编写程序实现输出任意两个数值之间的所有素数,在过程中判断单个数是否素数。
  例1:内部过程。
  *MAIN.PRG文件代码如下:
  INPUT TO X1
  INPUT TO X2
  FOR M=X1 TO X2
  FLAG=.T.
  DO PRIME WITH M,FLAG
  IF FLAG
  ?M
  ENDIF
  ENDFOR
  CANCEL
  PROCEDURE PRIME
  PARAMETERS N,FLAG1
  K=INT(SQRT(N))
  J=2
  DO WHILE J<=K .AND. FLAG1
  IF MOD(N,J)=0
  FLAG1=.F.
  ENDIF
  J=J+1
  ENDDO
  RETURN
  例2:外部过程。
  *MAIN.PRG文件代码如下:
  INPUT TO X1
  INPUT TO X2
  FOR M=X1 TO X2
  FLAG=.T.
  DO P1.PRG WITH M,FLAG
  IF FLAG
  ?M
  ENDIF   ENDFOR
  CANCEL
  *外部过程文件P1.PRG代码如下:
  PARAMETERS N,FLAG1
  K=INT(SQRT(N))
  J=2
  DO WHILE J<=K .AND. FLAG1
  IF MOD(N,J)=0
  FLAG1=.F.
  ENDIF
  J=J+1
  ENDDO
  RETURN
  在例1中将内部过程PRIME和主程序放在同一个文件中,并放在主程序的后面,程序运行时从主程序开始,当执行到命令DO PRIME WITH M,FLAG时,转去执行过程PRIME,其中PRIME是过程名。用外部过程实现时,主程序和外部过程分别存放在两个程序文件中,主程序文件调用时使用命令DO P1.PRG WITH M,FLAG,其中P1.PRG是外部过程保存的文件名,另外在外部过程文件中不需要使用“PROCEDURE <过程名>”语句定义过程名,因为过程名不起作用,调用时使用的是文件名。
  此外,如果在调用过程时需要返回数据给主调程序,此时不能通过RETURN命令返回,因为使用“DO”命令调用过程时,过程中的“RETURN”命令不能返回数据(即使使用“RETURN表达式”形式,也不能将表达式的结果返回,此时的表达式不起作用)[3]。这时可以通过传地址的方式来实现将过程的运行结果传回调用处。在程序中使用变量“FLAG”作为过程调用的返回值,过程调用前“FLAG=.T.”(即假定被判定数据为素数),调用过程时将实参FLAG的值传递给形参FLAG1(此时FLAG1=.T.),在调用过程中判定数据是否能整除,若能整除则修改变量“FLAG1”的值为“.F.”,若所有的除数都不能整除则FLAG1的值不变。调用过程结束时将形参N的值传回给实参M,将形参FLAG1的值传回给实参FLAG,即通过传地址的方式在调用过程中实现将运算数据返回调用处。
  1.3 函数
  VFP中函数有两种类型:库函数和自定义函数。其中库函数是VFP系统为用户提供的内部函数,用以实现一些常用的功能,用户可以直接调用。自定义函数是用户根据需要自己编写的函数(即自定义函数)[3]。
  自定义函数格式:
  [FUNCTION <函数名>]
  [PARAMETERS <参数表>]
  <命令组>
  RETURN [<表达式>]
  函数的调用形式是:
  <函数名>(<自变量表>)
  例3:将例1用过程编写的求素数的程序改写成用函数来实现。
  INPUT TO X1
  INPUT TO X2
  FOR M=X1 TO X2
  IF PRIME(M)
  ? M
  ENDIF
  ENDFOR
  CANCEL
  FUNCTION PRIME
  PARAMETERS N
  FLAG=.T.
  K=INT(SQRT(N))
  J=2
  DO WHILE J<=K .AND. FLAG
  IF MOD(N,J)=0
  FLAG=.F.
  ENDIF
  J=J+1
  ENDDO
  RETURN FLAG
  在例3中用“RETURN FLAG”命令给函数返回一个值,事实上在函数调用过程中通过RETURN命令最多只能返回一个值到函数调用处。若想返回多个结果只是使用RETURN命令是无法实现的。
  为了对比子程序、函数、过程三种结构的异同,现将上述程序用子程序的方式来编写,如下所示。
  例4:
  *MAIN.PRG文件代码如下:
  INPUT TO X1
  INPUT TO X2
  FOR M=X1 TO X2
  FLAG=.T.
  DO P2
  IF FLAG
  ?M
  ENDIF
  ENDFOR
  CANCEL
  *子程序文件P2.PRG代码如下:
  K=INT(SQRT(M))
  J=2
  DO WHILE J<=K .AND. FLAG
  IF MOD(M,J)=0
  FLAG=.F.
  ENDIF
  J=J+1
  ENDDO
  RETURN
  在例4中利用局部变量的特点,局部变量的作用域是在本级和下级程序中都可以使用[4],因此在子程序P2中判断数据M是否是素数,然后修改局部变量FLAG的值,调用子程序“DO P2”后,判断变量“FLAG”的值,返回为真时,M是素数。
  2 三种方式调用形式探讨
  从以上的4个小程序可以看出,在VFP中通过子程序、函数、过程都可以实现模块的编写,三种方式功能相同。虽然在VFP中模块的实现方式分成这样的三种方式,但实际上这三种形式也不是泾渭分明的,也就是说无论它们的编写格式和调用格式都不是固定不变的。上面介绍的格式是人们通常习惯的一种编写和调用格式。对于子程序、函数、过程都可以采用 “<函数名>(<自变量表>)”或“DO 过程名 WITH <参数表>” 的调用形式。例如在调用子程序时也可以使用函数的调用形式即 <函数名>(<自变量表>),同样调用函数时也可用DO <文件名>的形式来执行。下面以求圆柱体的体积为例,对比在子程序、过程、函数中采用不同的调用方式时,源程序的异同。
  例5:
  *子程序的一般调用格式,MAIN.PRG程序代码如下:
  INPUT TO R
  INPUT TO H
  V=0
  DO P3.PRG
  ?V
  *子程序P3.PRG代码如下:
  V=PI()*R^2*H
  RETURN   例5是采用一般的子程序格式编写和调用的,将这个程序改成使用函数格式调用,修改如下:
  例6:
  *子程序采用函数的调用格式,MAIN.PRG程序代码如下:
  INPUT TO R
  INPUT TO H
  V=0
  P3(R,H) && DO P3 WITH R,H
  ?V
  *子程序P3.PRG代码如下:
  PARA R,H
  V=PI()*R^2*H
  RETURN
  程序调试运行后,验证结果是正确的。说明子程序的调用也可使用函数的调用格式,但此时需要注意的是在子程序中必须要有“PARAMETERS”语句,因为在函数调用过程中要将实参的值传递给对应的形参,实参和形参必须一一对应,所以PARAMETERS语句不能缺少。在上述程序中也可将“P3(R,H)”命令改写成“DO P3 WITH R,H”,此时也存在实参和形参之间的数据传递,而且从外观上看更像是外部过程形式了。
  再将例6改成用函数实现求圆柱体的体积,代码修改如下:
  例7:
  *函数一般调用格式:
  INPUT TO R
  INPUT TO H
  ?CYLINDER(R,H)
  FUNCTION CYLINDER
  PARA R,H
  V=PI()*R^2*H
  RETURN V
  例8:例7中的函数不变,将函数调用方式该为DO命令调用。
  INPUT TO R
  INPUT TO H
  V=0
  DO CYLINDER WITH R,H
  ?V
  FUNCTION CYLINDER
  PARA R,H
  V=PI()*R^2*H
  RETURN V
  对比例7和例8两个程序,对于函数的调用也可使用“DO 函数名 WITH 参数表列”形式,但调用过程结束时,不能通过RETURN命令来返回运算结果,此时RETURN后的表达式不起作用。在该程序中采用了局部变量V,在函数调用过程中修改变量V的值来实现数据的传递。从这个例子中看出,虽然编写的是函数,但是在调用时用的是“DO”命令,此种调用方法不能通过RETURN命令来返回运算结果。
  例9:将该程序用过程形式实现,修改如下:
  *过程一般调用格式
  INPUT TO R
  INPUT TO H
  V=0
  DO CYLINDER WITH R,H
  ?V
  CANCEL
  PROCEDURE CYLINDER
  PARA R,H
  V=PI()*R^2*H
  RETURN
  例10:将例9的过程调用方式改为“过程名(实参表列)”形式。
  INPUT TO R
  INPUT TO H
  ?CYLINDER(R,H)
  PROCEDURE CYLINDER
  PARA R,H
  V=PI()*R^2*H
  RETURN V
  程序调试运行后,验证结果也是正确的。对比上述的两个程序,也可使用“过程名(实参表列)”形式调用过程,而且采用这种形式调用过程时还可以通过RETURN命令返回结果。
  从以上程序的验证结果来看,在编写函数和过程时,不管是用“FUNCTION”还是“PROCEDURE”都是一样的,关键是看调用时使用的是“DO”命令还是“函数名(实参表列)”。这两种形式调用时都实现实参到形参数据的传递[5]。若采用“函数名(实参表列)”形式调用,调用结束后通过“RETURN”命令可以返回一个结果给调用处;若采用“DO”命令调用函数或过程,因为无法通过“RETURN”命令返回结果,此时可以采用全局变量或局部变量的方式来实现在上下级程序之间数据的传递,或是在“DO 过程名 WITH <参数表>”中通过在“参数表”中多增加参数方式来实现(即将调用函数或过程需传回的数据另外设成一个参数),在函数或过程调用结束后通过将形参的值再传递给实参,比如例1中判断一个数是否素数的内部过程的实现方式就属于这种。
  同理,子程序也是一样的,只是将过程名或函数名变成了程序文件名,调用时同样可以采用两种形式。
  3 结束语
  子程序、函数、过程本质上是一样的,在调用时都是通过变量的作用域和实参—形参数据传递两种方式实现数据的传递的。调用时可以使用“DO”命令或“函数名(实参表列)”两种形式。当调用形式不同时,程序也略有不同。经过以上分析,作者认为虽然很多书中把模块化的程序设计方式分成子程序、过程、函数三种,我们仍然可以把它们都看成是子程序(因为它们都不能够单独运行)。这样,子程序就包括两种:一种是子程序单独保存在一个程序文件中(即外部子程序),另一种是子程序和程序在同一个文件中(即内部子程序),此时需要给子程序一个标志(即过程名或函数名)。
  外部子程序单独在一个文件,此时子程序可以和普通程序相同结构,也可包含PARAMETERS子句。外部子程序格式和调用方式如表1所示。
  表1 外部子程序格式及其调用方式
  [[格式\&调用方式\&普通子程序\&DO\&PARAMETERS\&DO 子程序 WITH <实参表列>
  子程序(实参表列)\&]]
  内部子程序和主程序在同一个文件,子程序必须放在主程序的后面。内部子程序格式和调用方式如表2所示。
  表2 内部子程序格式及其调用方式
  [[\&调用方式\&PROCEDURE 子程序名\&DO 子程序 WITH <实参表列>
  子程序(实参表列)\&FUNCTION 子程序名\&DO 子程序 WITH <实参表列>
  子程序(实参表列)\&]
  ]
  VFP以其本身的优势,被许多高校作为一门计算机基础课程。笔者在多年从事VFP教学的过程中,不断尝试总结,最终发现,在讲述模块的程序设计方法时,采用以上的方法进行讲解,有利于学生掌握模块的含义及其编写,达到事半功倍的效果。此外,VFP的教学还需要深入探讨。
  参考文献:
  [1] 刘卫国.Visual FoxPro程序设计教程(第2版)[M].北京邮电大学出版
  社,2005.
  [2] 柳青,刘顺来.Visual FoxPro程序设计教程(第2版)[M].高等教育出版
  社,2009.
  [3] 潘晓南.Visual FoxPro数据库应用技术[M].中国铁道出版社,2004.
  [4] 刘丽.Visual FoxPro程序设计[M].中国铁道出版社,2005.
  [5] 张莹.Visual FoxPro数据库与程序设计教程[M].机械工业出版社,
  2007.
其他文献
公立医院原有分配方法多是“成本核算、节余分配”,过分强调了医院的市场属性而忽视了医院的公益职能。本文所探讨的在新形势下综合医院住院部绩效工资考核,将薪酬管理与绩效
以水稻高产优质技术应用行为为研究对象,把江西省种稻大户作为基本研究视角,通过对1 077户数据进行整理分析,发现资金制约因素为种稻大户考虑高产优质技术时最为担心的问题。
在对江西省2009年以来城乡一体化发展实践探索进行系统总结的基础上,结合新时期的社会经济发展特征,对进一步推进城乡发展一体化进行了理论思考,提出了推进城乡发展一体化的
以农户态度为中介变量构建理论模型,采用江西省1 042户农户下乡家电购买意向的微观调查数据,利用多元线性层次回归方法实证分析了参照群体不同维度影响对农户下乡产品购买意
近年来我国食品安全事件频发,政府出台了一系列法律法规,旨在通过建设食品安全追溯体系以实施沿供应链的纵向监控,但收效甚微。而邻国日本通过在农协内部开展“生产履历记账运动