VBA 类模块系列之五——使用你的第一个类

第二篇中我介绍过,类就是做饺子的塑料模具。到目前为止,我们做好了一个叫做Person的模具。现在我们要用这个模 … 继续阅读“VBA 类模块系列之五——使用你的第一个类”

第二篇中我介绍过,类就是做饺子的塑料模具。到目前为止,我们做好了一个叫做Person的模具。现在我们要用这个模具做真正的饺子了。

还记得你是怎样使用ADODB库中的Recordset对象的吗?你在窗体代码模块,或者标准代码模块里面声明一个Recordset变量(Dim rst as Recordset),然后使用Set rst = New Recordset 语句创建一个Recordset对象,将rst指向这个新创建的对象。这里我们也是一样的操作:插入一个标准代码模块,然后添加一个子程序Test(),在子程序中添加如下代码:

现在对象变量objPerson指向了一个真正的“饺子”了,这个“饺子”有3个属性:姓名,性别,场合。现在这3个属性都是空白的,什么值都没有。所以我们要先给它们赋值。

Option Compare Database
Option Explicit

Sub test()
    Dim objPerson As Person
    Set objPerson = New Person
    
    objPerson.Name = "赵冰冰"
    objPerson.Gender = "女"
    objPerson.Situation = "一般"

End Sub

属性赋值以后,我们就可以调用类的方法了,目前只有一个方法Speak。

Option Compare Database
Option Explicit

Sub test()
    Dim objPerson As Person
    Set objPerson = New Person
    
    objPerson.Name = "赵冰冰"
    objPerson.Gender = "女"
    objPerson.Situation = "一般"
    objPerson.Speak
End Sub

我们执行一下这个子程序,一个这样的信息窗口就会跳出来:

我们成功了!感觉如何?我们创建了自己的类,又用它实例化了一个对象,设置了它的属性,调用了它的方法。

欣喜之余,冷静的读者可能会提出一个问题来:调用类的方法Speak前,还需要设置这么多的属性,忙乎了半天,这个类也没帮到我们多少事情,何必呢?好吧,你说得对。如果对象在创建的时候,某些属性就能自动初始化,比如让场合(Situation)这个属性默认设置为“一般”,那就好了。我们就可以少初始化一个属性了。

这个问题当然是有办法解决的。这正是下一篇我们要谈到的:类的实例化事件。

VBA 类模块系列之四——创建你的第一个类

前三篇终于啰嗦完了,牛逼也吹完了,我们现在来创建一个类。 首先在VBE里面,选择插入菜单-类模块,一个空白的类 … 继续阅读“VBA 类模块系列之四——创建你的第一个类”

前三篇终于啰嗦完了,牛逼也吹完了,我们现在来创建一个类。

  1. 首先在VBE里面,选择插入菜单-类模块,一个空白的类模块就创建好了。

2. 接下来,要想一下,我们用这个类来干嘛用?还没想好去哪里,我就出门了,哈哈。这个应该放在第一步。好吧,比方说我们现在要用这个来为模拟一个人(Person),第二篇里面谈到,类的接口是由属性方法事件构成的,那么我们要模拟人的哪些属性,方法,事件呢?

我们先来考虑属性(Properties)

人的属性太多了,姓名,性别,年龄,身高,体重,民族等等。我们弄简单点,只考虑他的姓名(Name)和性别(Gender)。

我们确定了目标,就可以开始行动了。因为我们要用这个类来模拟一个人(Person),那首先我们就将这个类的名字改成Person。这个很简单,在左下角的名称属性里面,将“类1”改为“Person”。然后我们在类中建立姓名和性别这2个属性。

为类创建一个属性,最简单的方法就是在类的头部声明一个公共变量。我们申请2个:

Option Compare Database
Option Explicit

Public Name As String
Public Gender As String

3. 属性添加好了,接下来考虑方法。这个类需要什么方法呢?因为这个类就只有2个属性,姓名和性别,比如某个美女,她叫赵冰冰,你会怎么称呼她呢?这个得看你跟她的关系了。如果你们之间很陌生的话,你会叫她“赵小姐”,如果是在非常正式的场合,你应该叫“赵女士”,如果你想撩她,你会叫她“小姐姐”。我们给这个类添加一个名叫称呼(Speak)的方法。但是根据什么来确定你称呼的方式呢?我们需要再多添加一个确定场合(Situation)的属性,有了这个属性,我们才好确定该用何种方式称呼她。

Option Compare Database
Option Explicit

Public Name As String
Public Gender As String
Public Situation As String

Public Sub Speak()
    Select Case Situation
        Case "一般"
            MsgBox Left(Name, 1) & "小姐"
        Case "正式"
            MsgBox Left(Name, 1) & "女士"
        Case "撩"
            MsgBox "小姐姐"
        Case Else
            MsgBox Name
    End Select
End Sub

我们添加好了如上的代码,我们只分了3种场合,如果不是这3种场合,我们就直接称呼她的姓名好了。

我们的第一个类就这样轻松设计好了。

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事件编写代码,来实现,但万一修改又被撤销了呢?将业务逻辑代码散落在每个窗体里面,也不值得提倡。窗体最理想的状态,是只做用户交互。

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