尽管我过多地使用类来完成作业,尽管这也带来一系列的问题,而难道我不是为了处理问题而选择这个行业的吗?碰到的问题越多是否意味着我处理问题经验越丰富呢,开始懂得避开问题是否证明我开始成熟呢?
类更应该是可视的而不是用过程定义的。并不是什么基类都需要都要重新建立一个基类库,如 MyBase.Vcx ,但既使是标签,既使并不需要它做任何事,我仍然把它将存成一个名为 _MyLabel 的基类。我想也许以后我可以使用在 Init 的感应操作系统并重置它的 Caption以自适应简繁体操作系统。再加上 Caption_Assign 事件我想它是能胜任这个工作简繁转换的工作的。就是有“为了也许为了以后”可以扩充其功能的这个理由,我使用类打造我的程序。
使用类,并不是不使用过程。但我想过程更应该也更贴切的称呼应为函数。既使是我们用得最多的 USE 指令,我依然另定义了一个MyUse 的函数以取代它,我们常用的 USE 格式必竟有限,或者在大多数的情况下,我们在一个表单里要 USE 的某文件己经被误删除了,那个在这个函数里,它就会检查文件是否存在,是否可以打开,是否能独占打开是否己无效打不开了…,然后并给出我们喜欢的错误报告。而超出 MyUse 所能胜任的常规 USE 工作,我还可以使用 USE 来摆脱 MyUse 的限制。
基类的所在目录不应该发生变化,它是独立一个目录,因为没有象 Home() 这样函数来指出它的位置,所以我的目录名是从来不更改的,一旦更改所有的派生类都要调整很久才能恢复过来甚至崩溃,因此确定这个目录名是要慎重。之后,你就可以在任何项目的任何表单任何过程可以用
NEWOBJECT("MySaveSet" ,"\MyVcx\ConverXy.vcx" )
这样的 "\xx\yy" 格式的访问目录名可允许我不管项目在哪里目录在哪里我都能快速地把类加载到我的程序里,也只有这样才能让它修正了 BUG 所有的项目所有的地方都修正了 BUG。不应该只让它做为一
个项目子目录。
我只把帮助文件与我的项目一起打开,在使用任何一个系统函数时,我都应该去查找关于它的文字解释而不是如何使用它的指令格式,那时候我就会经常看到这样的文字:某某某设定会影响这个函数的返回值,某某某函数只对当前工作期有效,在某某某情况下某某某函数会
失效或异常。那么,在类里在使用任何函数时,要记得把影响到它工作的那些环境设定保存起来,然后再把环境设置成那个函数可以完成你预期工作的值,最后是恢复原有的环境设定。好听一点的称呼是:保存现场与恢复现场。
永远不要以为类只可以放在表单,要记得类是被载入内存并在任何地方使用,我可以用菜单载入它,我可以用过程载入它。我知道在某个条件不被满足时,那个类是不需要加载到内存的,但把它放在表单基类里,显然我的表单的基类要加载的东西就太多了。所以在任何一个类里,如果需要表单信息,那么不应该出现在是 ThisForm 字样,使用 _Screen.ActiveForm 更好些,自然你也不能假设一定有_Screen.ActiveForm 这个对象存在。我深知,表单也是一个对象而己。
对于内存变量,用 VarType(lcMyAlias) 检查它的类型以获得更快的速度,对于任意对象的属性,使用 Type("This.MyAlias") 来确定它是否存在合法值与类型,我知道这样能保证类的健壮与稳定。
用 Local 声明的变量不是局部的,它存在周期直到它的上下代码执行结束才会消失,因此如果在它之下的代码载入了一个类,而你的类的一个变量与它同名,那么那个变量还没初始就有值了。因此我在类里,任何变量的声明之前都用 PRIVATE lcMyAlias 把它们隐藏起来,再用 Local lcMyAlias 声明一次。最好的方法莫过于类的所有变量都有一个独一无二的开头字符如 Local lcMyAlias ,而在项目的变量声明只使用 Local cMyAlias,这样永远不会有问题。
VFP 取出的字段值的优先级别远高于变量的级别,因此我在类于 m.lcMyAlias 我绝对不会省略这个 m. 这两个符号,我知道终有一天会有这么一个表有这么一个字段名为 lcMyAlias 的字段值会被先取出,而我定义的可怜的变量一旁哭泣看着整个类崩溃并没有完成它应该完成的任务。并且我从来不会嫌麻烦更不会嫌变量名太长,我非常乐意使用 lcMyStringExpression 来做为变量名。我从来不在类里使用低于 10 个字符的变量名。避无可避的 & 表达式,由于不能使用 m. 来严历指定值是取自变量,那么,它的表达式会长达 20 个无意义的字符,最典型的例子莫过于 ON ERROR &lcThisIsTheOldErrorCode 来恢复以前的 ON ERROR 现场。
另一个也为精典的就莫过于保存现场用 lcOldDeleteSetingExpression = SET("DELETE") 恢复现场用SETDELETE&lcOldDeleteSetingExpression。另外在类里忘掉PUBLIC 的存在也许对于找到问题的所在是极有帮助的,更不要在类里 RELEASE lcMyVar,也许我会释放掉呼叫这个类的上层过程的Local lcMyVar。
保护或隐藏类的属性与方法是一个很好的主意,这会让类在使用时一目了解而不会看到太多不应该看到的东西,如果我这么做了,那么我会在类的 Init 事件里不写任何一句代码或不在 Init 事件里访问任何隐藏的方法与属性,而让类有一个 MyInit 方法以初始化这个类,如果不这样做的话,那么想给我一个惊喜的,通常是 C00000005 或者一大堆错误报告指出某对象(没错,是对象而不是属性)不存在,实际上对象是存在的,就是调试器也显示了它的存在,但程序就是说那个对象不存在我奈它何。
调试类是最痛苦的,所以我想我更应该花很多时间去熟悉如何使用 VFP 的调试器并学会监视一个变量其值的变化,我想学精了 SET STEP ON 与 F5,F6,F7,F8 并没有花去我多少时间我己能初步调试一个类了。
类不可能一次性规划好,不可能对抗任何不可预知的环境,所以类一定要进行上百次的更动才能稳健,最精典的例子莫过于 GETENV()了,因为在 WINDOWS 的不同操作系统上,它有不同的反应。最伤我心的例子莫过于 APRINTERS(),在 WINDOWS 98 与 WINDOWS 2000里,它返回的值让我目瞪口呆。
我命令自己背下所有事件的发生顺序,很多事件是成对发生的。如 Init 与 Destory 事件,Load 与 Unload 事件。这样我就知道在什么时候创建对象在什么时候释放对象,我永远不会在 Load 事件里创建任何对象,因为在 UnLoad 事件发生时对象己经全部释放完了,因为成对发生的事件不是 Destory ,所以我的 Destory 事件的代码并不敢假设那个对象己经创建了而去尝试释放它。
不要在为类里使用 #DEFINE,不要在任何一个可扩充功能与未完成全部设计的类里使用 .H 头文件。几个月后,我会忘记它的存在,但它不会忘记。你应该在类的任何事件方法所有代码的的开始注释与声明变量,这样你一打开代码查看器就能看到它们,而不是让 .H 文件潜在地威胁你变量的值,#DEFINE 优先级别之高不亚于 PUBLIC ,如果你得到一个类,并且将它并入了你的类中,如果那时你的类库发生异常,请点击菜单,选择类->包含文件,如果它的值不为空,那么,杀手一定是它!
你会喜欢类的 ERROR 事件的,它是你所见过的最美的MM。


488

被折叠的 条评论
为什么被折叠?



