VBA 类模块系列之三——为什么要使用类

本篇我只想说一件事实:在国外的Access VBA开发者社区,会使用类是一件很酷的事情。大家去国外论坛验证一下 … 继续阅读“VBA 类模块系列之三——为什么要使用类”

本篇我只想说一件事实:在国外的Access VBA开发者社区,会使用类是一件很酷的事情。大家去国外论坛验证一下就知道了。接下来的内容,吹牛逼的成分比较多,但是作为一个严肃的系列文章,该吹的牛逼还是要吹的:)。大家要是忙,可以直接跳到下一篇。

可以说,你在Access中的绝大多数编程任务都可以用标准模块来完成。那么你为什么要使用类模块呢?这个问题可以从以下几个角度来看。

数据和行为的封装

VBA的类模块能带给你的一个最大的好处,就是你可以将一些相关的数据和行为封装在这个类模块中。

我记得好几年前,我还在市场部做数据分析预测的时候,经常要查将来5年还是10年每年节假日的具体日期。元旦,五一,国庆这3个假期,最简单了,每年都是固定的日期。清明和中秋就比较麻烦了。中秋是按农历,每年都不一样,清明是按节气,虽然每年都差不多是4月4日或者5日,但是你拿不准到底是哪一日。为了一劳永逸的解决这个问题,我在网上找到了一个Excel VBA 类模块,里面有封装了天干,地支,节气,星座等等你能想得到的数据,还有很多函数,公有的函数提供对外的调用,私有的函数供类内部计算使用。有了这个类,你能将任何将来的日期转化为对应的农历日期。喜欢刨根究底的我,特意去研究了类中的代码,但是还是看不懂,不是代码看不懂,而是对农历历法一无所知,所以不知道代码为什么要这么写。我进一步去研究农历历法,结果我找到了一片国外的论文,看着从中文翻译成英文,又在我脑中转成中文,那种感觉特别别扭。从外国人对中国的农历历法的研究中,我得出一个结论:从地球绕太阳公转的角度来看,农历比公历更加准确。呃,这牛逼吹到民族自豪感上去了:)

一个类中,既有数据,又有方法,它就能实现一定的特定功能。难道这个就非得用类模块来实现吗?标准模块不行吗?这是个很好的问题,我们来看看如果是标准模块,怎么来实现。标准模块中,你可以声明一些私有的模块级常量和数组变量,将这些天干,地支,节气数据放在其中,然后私有和共有的函数或方法保持与类模块中的一致。传入参数调用某个公有函数,第一次调用的时候,模块及的变量当然是没有初始化的,需要检查一下是否初始化,若没有就初始化一下,然后执行公有函数的代码,也能得到一样的结果。你唯一不能做的,就是同时创建一个类的多个实例。标准模块不存在实例的说法,它一旦被调用,永远只在内存中保留一份私有模块级变量数据。所以你无法同时创建2个日期对象数据。一旦你遇到需要同时保留一份以上的日期数据的时候,你能做的,就是再创建一个一模一样的标准模块。这就回到了该系列第一篇里面谈到的,在多处维护相同代码的窘境。

将复杂的实现逻辑隐藏起来

这个好处是显而易见的。我并不需要事先知道农历历法是怎样计算的,就能将一个公历日期转换为农历日期。我只需要知道类的接口,知道如何调用它就好了。这种示例在Access中还有很多,比如ADODB库中的数据集Recordset类,天知道它是怎么将表中的数据读取到内存,还有一个游标说它目前指向的那一行数据,你执行一下MoveNext方法,它就指向到了下一行。我只需要知道这样操作,就能得到相应的结果,至于它背后是如何实现的,你可以心安理得的保持无知状态。因为这不是你需要操心的事情。正式因为类有这种独特的隔离特性,使得程序员与程序员之间的分工协作变得容易。一个大型的项目就是由很多程序员合作编出来的。在这里你也能感受到接口的重要性。还是那句话,一旦发布了的接口,就不能去修改了,但是可以添加新的接口。

让程序员之间的分工写作变得容易

上面已经谈到了,这里谈谈自己的经验。我使用Access一般都是做一些部门级的系统,说大不大,说小也不小,都是一个人开发,还未有与他人合作开发的情况。所以不存在分工的问题,尽管如此,我还是习惯将用户界面与数据读写相分离,中间用类来做2层之间的交互,同时还有一些其他的辅助类,实现一些特定的商业逻辑。当然你可以说这已经脱离了Access的快速开发的初衷,谁说不是呢?Access初学者习惯使用绑定窗体,但你知道的,用户的需求是很刁钻的,我举个例子,绑定窗体如何能保存数据更改的历史记录?在多用户环境中,你还需要记录下是谁在什么时间做的更改?是将哪个旧数据改为哪个新数据的?当然你可以在绑定窗体中,对每个绑定的控件的change事件编写代码,来实现,但万一修改又被撤销了呢?将业务逻辑代码散落在每个窗体里面,也不值得提倡。窗体最理想的状态,是只做用户交互。

这些个人风格上的事情,仁者见仁智者见智了。牛逼吹完了,欢迎拍砖:)

 

《VBA 类模块系列之三——为什么要使用类》有一个想法

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注