我眼中的Visual FoxPro 8.0(一)2007-05-09 boe 鸣谢经常来 BOE 的朋友都知道,我早就是一个业余的 Foxer 了,随着时间的推移,每一次写东西都是惴惴不安的,真的担心弄出一些误导言论或者是贻笑大方。每一次完成初稿我都会给一些朋友预览,好听听他们的建议。漫步者、Boby、将来是我 这三位网友就是我的第一批读者,感谢他们一次又一次读那些晦涩的言语、理解不成熟思想。特别是漫步者,几乎成了我的私人秘书,就拿这篇东西来说,正文中所有的小标题都是他加上的。他说,这样能让读者容易看懂……成文后,属上的都是我的名字,真是有白占别人劳动的嫌疑,这里向这些朋友表示深深地感谢!写在开始那一日,我连夜等待 Visual FoxPro 8下载,直到凌晨2点,实在是熬不下去,这才睡下;4点时分,被闹钟催醒,睡眼朦胧中看到了 Visual FoxPro 8 的下载连接,迷迷糊糊的也知道动作是怎样完成的,反正早上醒来 Visual FoxPro 8 已经在我的硬盘上了。解压、安装,一阵兴奋难以言表;忽又想起,还要上班,于是烧盘、走路……这样,开始了我的 Visual FoxPro8 探索之旅。原来以为,已经看过大量原版资料(感谢 夜来香、RMH、Fbilo 他们已经翻译这些东西,英文不好的朋友现在也能享用了),我研究Visual FoxPro 只需要少量的精力。嘿嘿,谁知道:我竟然花费了整整10天才看完了我所感兴趣的东西。而且是每天作战到凌晨,家人意见不少,但是他们哪知道我乐在其中呢?今年10月,微软公司如期发布了 Visual FoxPro 8b 版,这是自 Visual FoxPro 3 以来又一个精彩的版本,一下子吸引住了全球 Foxers 的眼球!下文是我学习、探索 Visual FoxPro 8b的一些感受,愿与读者分享。(一)结构化异常处理经常有人问我,你认为 Visual FoxPro 最需要改进的地方在那里。我总是不假思索地回答:异常处理!期盼它能拥有结构化异常处理机制,把异常及其处理限定在最小的范围之内,使代码的封装更优。Visual FoxPro 8 以前对异常处理还限于全局 On Error 例程和对象的 Error 的事件,它们都有这样一个毛病:一旦出现了异常,程序就必须跳出正在执行的程序模块,执行异常处理例程,这时发生异常前执行的程序模块的上下文已经丢失殆尽,系统很难调整到正常状态或者给调用接口一个明确的答复!Visual FoxPro 8的 Try…Catch…Finally…End Try 结构让人激动不已,它帮助我们方便的抓住“异常”,即时针对各种异常做出反应,缩小异常的影响范围,保护系统的运行状态;也使得程序模块的封装性更好。想想以前应付“异常”而设计的各种方案,一夜之间成了昔日黄花、显得那样苍白无力,真是“沧海变桑田”啊!仅此一项增强,Visual FoxPro 8就已经光彩夺目,相信任何开发人员都经不起“结构化异常处理”的诱惑,升级到Visual FoxPro 8!(二)CursorAdapter 类Visual FoxPro 8提供的CursorAdapter 类也是大家所津津乐道的。CursorAdapter 是一个基于松散耦合思想设计的对象化的 Cursor 处理模型。1、VFP8以前的数据处理在 Visual FoxPro 8 之前,我这样评价在 Visual FoxPro 里的数据处理:灵活而强健,面向记录处理为主、面向集合处理为辅,采用过程化编程模型,但可以利用面向对象的 XBase 语言自行封装数据处理对象。说到Visual FoxPro 处理数据的灵活和强健,归根到底是Visual FoxPro 同时支持 XBase语言和SQL 语言。XBase 语言善于对记录的梳理,这种处理往往是基于“行”的模式;SQL 语句对数据的处理是根据“集合”的概念,按照条件取得“集合”,然后处理。无论采用 XBase 语言处理数据,还是使用 SQL语言,Visual FoxPro 默认提供面向过程的数据处理编程模型,而不是流行的面向对象的编程模型。(当然,Visual FoxPro 并不限制开发人员编写自己的数据处理对象。)那么在 Visual FoxPro 中所谓的“数据”到底是什么呢?是 Cursor!在Visual FoxPro 中整个数据处理是围绕着 Cursor 进行的(而不是 DBF),所以对象化数据处理模型也应该从 Cursor 着手!2、面向对象的数据处理器在 Visual FoxPro 设计对象化的 Cursor 是没有太大的意义的,这句话很突兀、让人摸不到头脑!我们用典型的对象化游标――ADO 组件的 RecordSet 做分析。可以发现RecordSet 中定义了数据集合的来源、数据集合的结构(表结构)、数据的更新回送方式,另外RecordSet还能够对数据集合进行操作,诸如Move、Find、Delete之类的方法。在 Visual FoxPro 里对象化 Cursor,是不是要照搬 RecordSet 的一套呢?如果由我们来设计这个构架,我们如何取舍呢?我觉得没有必要实现对 Cursor 本身的封装,这样是在自残,我刚才已经说过了:整个 Visual FoxPro 对数据的处理就是对 Cursor 的处理,如果封装了Cursor,就背离了整个体系的构架思路,同时也放弃了 Visual FoxPro 对数据处理的“灵活与强健”的特色。这就是前面提到的“在 Visual FoxPro 设计对象化的 Cursor 是没有太大的意义的”。对象化 Cursor 没意义,那么我们究竟需要什么呢?用一个面向对象的 Cursor 的处理(管理)器来管理 Cursor的数据来源、Cursor 的数据结构、Cursor 中数据变动的更新回送;而Cursor 依旧是传统意义上的 Cursor,没有任何改变,依旧可以用 XBase 或者 SQL 语言对直接 Cursor 进行处理――这才是我们需要的。说到这里,大家会问了,这不就是DBC 中的视图吗?它们在实现的功能上确实有点像,但实质上是有差别的:首先,视图是 DBC 的对象(组件),利用视图设计的系统对 DBC 的依赖性大,不符合多层体系构架的思路。而我们的对象化 Cursor (处理)管理器与 DBC 无关,完全是程序设计级别上的概念。从多层体系设计的观点看,属于业务逻辑层次。再者,视图是数据库中的概念,灵活性差、可控制性差;而对象化 Cursor (处理)管理器就不一样了,作为对象,具备了面向对象程序设计的一切好处,很容易定义、改变、维护,更能够继承使用,这都是使用视图所办不到的。随便就能举出几个视图弱势的例子,有时候数据集合的结构一致,但是数据来源不一样,就必须麻烦的设计几个视图,而使用对象化 Cursor (处理)管理器就只需要改变数据来源属性;又例如,数据来源相同、数据集合结构相同,只不过获取数据的条件不同(Where 子句构造不一样),用视图就必须设计新的视图,而使用对象化 Cursor (处理)管理器只需要改变相关属性即可……说到底:视图是数据库的概念,具备的是数据库对象(组件)的特性,而不具备编程语言的特点,对象化 Cursor (处理)管理器解决的就是这个问题。3、松散耦合 在视图时代或者是RecordSet时代采用的是紧密耦合的思维,说的直白一点,就是:数据从哪里来就更新到哪里去,程序员并不能在其中做什么干涉,一旦执行了TableUpdate(),就自动更新数据源,没有商量的余地!松散耦合提供了一种开放的模型,它以 Cursor 为中心,从本质上认识到 Cursor 与数据源的相互关系是:数据获取和变动更新回写。数据获取就是 SQL-Select操作、数据更新回写就是SQL-Insert、SQL-Update、SQL-Delete。松散耦合模型提供 Cursor 数据来源的Select子对象、Cursor 数据添加回写数据源的 Insert子对象、Cursor 数据修改回写数据源的 Update 子对象、Cursor数据删除回写数据源的 Delete 子对象。由于从构架上把Cursor与数据源的各种互动操作分割开来,再辅以事件模型,这就给了开发人员很大的编程余地!相比之下,视图虽然也采用类似的思路与数据源互动,但是它把整个互动过程作为一个整体看待,严严实实的包装起来,造成开发人员的参与性差。4、VFP8的CursorAdapter对象

让我们回过头再看 Visual FoxPro 8 提供的 CursorAdapter 对象,默认情况下支持四种数据来源,分别是:Native(本地数据)、ADO、ODBC、XML。请思考一下,为什么 CursorAdapter 能够支持几种性质完全不同数据来源呢,原因就是采用了松散耦合模型,让开发人员用自己的代码参与数据的获取,使得整个体系的扩展性大大增强,这就是松散耦合的魅力!概括VFP8中的CursorAdapter,它是:一个基于松散耦合思想设计的对象化的 Cursor 处理模型。CursorAdapter 既保留了 Visual FoxPro 对 Cursor 处理的传统优势,又引入了先进的编程模型和构架。再次强调它的特色:
- Cursor 本身没有被对象化,依旧是传统意义上的 Cursor,可以使用一切传统语句处理 Cursor。
- Cursor 的管理方式对象化了,可编程性更好,有利于代码的封装。
- 采用了松散耦合的设计思维,以 Cursor 为中心、但又分割了 Cursor 与数据源之间的各种操作、再加入事件模型,为开发人员提供了很多参与的机会。