网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > Delphi
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.Windows消息机制初谈.
.正确看待《Delphi高手突破》最后.
.在Delphi中处理数据库日期型字段.
.Delphi下常用转换(一).
.公布TstringGrid增强控件TcbStrG.
.远程控制篇:获得网络邻居所有机.
.关于时间函数.
.在DELPHI程序中使用ADO对象存取O.
.Delphi的TWebBrowser编程综述.
.设计模式、用Delphi描述-->Obser.
.在delphi中,如何把MDI工作区的粗.
.在Delphi.net中调用COM/COM+.
.进程查看器1.3版开发后记.
.ADO带密码的数据连接、查询一个记.
.Delphi和Office程序开发.
.Delphi托盘编程实战演练.
.Delphi控件制作技巧[一].
.Delphi数据库编程教程(六).
.Delphi深度探索-数据库明了的Act.
.在Delphi程序中调用控制面板设置.

Delphi中避免使用ClassName判断对象的类型

发表日期:2006-2-4


 

在公司原有系统的代码中,我看到了很多判别对象的ClassName属性进行分别处理的代码。而且似乎已经是处理类似问题的标准方法。但是其中可能会隐含一些问题。

首先,我们知道多态是面向对象的三大特性之一。所谓多态,其思想就是,对于不同的具体类型,我们可以通过相同的抽象接口进行访问,而不必关系具体类型的实现细节。就像下达通知:所有员工明天9点在人民广场集合。并不需要具体通知每个住在不同位置的人应该几点出发,走什么路线,因为这是具体的人的责任,而非通知下达者的责任。所以,在写到需要判断ClassName进行分别处理的时候,首先应该想到的处理方式是在父类中增加接口,通过子类override完成。如下面改变把图形大小的代码:
    for i := 0 to 图形列表.Count - 1 do
    begin
      图形 := 图形列表[i];
      if 图形.ClassName = '长方形' then
      begin
        长方形(图形).长 := 长方形(图形).长 * 2;
        长方形(图形).宽 := 长方形(图形).宽 * 2;
      end
      else if 图形.ClassName = '圆形' then
      begin
        圆形(图形).半径 := 长方形(图形).半径 * 2;
      end  
    end;
   
就可以在父类“图形”中增加“ChangeSize”方法,代码如下
    图形 = class
      ……
      procedure ChangeSize(rate: Integer); virtual;
    end;
   
    长方形 = class
      ……
      procedure ChangeSize(rate: Integer); override;
    end;
   
    圆形 = class
      ……
      procedure ChangeSize(rate: Integer); override;
    end;
在具体的图形类中实现大小改变的代码:
    procedure 长方形.ChangeSize(rate: Integer);
    begin
      长 := 长 * rate;
      宽 := 宽 * rate;
    end;
   
    procedure 圆形.ChangeSize(rate: Integer);
    begin
      半径 := 半径 * rate;
    end;
这样修改后,上面的代码就可以这样调用了:
    for i := 0 to 图形列表.Count - 1 do
    begin
      图形 := 图形列表[i];
      图形.ChangeSize(2);
    end;
这样代码的意图清晰了很多。

当然,在很多时候,出现判断ClassName的情况下并不能采用上边的解决方法。比如遍历Form的Cotrols并对不同的控件进行分别初试化。我们不可能去TControl中增加初始化方法,只有采用判别具体子类类型。那么这时我推荐采用is运算符而非直接比较ClassName。
is的用法,语句 aObject is TForm 在不同的aObject的类型情况下结果如下:
    aObject是TObject,结果为假;
    aObject是TForm,结果为真;
    aObject是TForm1,结果为真;
    aObject是TEdit,结果为假;
    aObject是nil,结果为假;
从上面示例可以看到采用is的一个优点,is可以判断是否子类的情况,比如我们在初始化控件的时候根据是TImage还是TEdit作不同的初始化,通过is判断处理。将来也许会采用TCoolEdit来美化界面,那么这段代码不需要更改,因为一个TCoolEdit是一个TEdit;而如果采用ClassName那么必须更改为子类的名字才行。

其次如果被判断的对象有可能为空,使用ClassName判断必须先判断对象是否赋值,否则就会出现内存访问错误。判断代表必须写为:if Assigned(aObject) and aObject.ClassName = 'TClass1';而采用is只需要写为if aObject is TClass1。
最后一个不采用ClassName作为判定的原因是,ClassName只是用来描述一个类的属性,字符串比较不能在编译期获得检查,如果存在拼写错误,或是大小写问题代码都会出现逻辑错误,而这种错误只有在运行期运行到这一语句的时候才会被发现。
    if aControl.ClassName = 'TEidt' then       //只有在你注意到Edit没有初试化时才会来检查这段代码;
    if aControl is TEidt then                   //无法编译通过;

综合上面所述,在需要判定一个对象的具体类型时,首先应该考虑通过多态处理避免这种分别特殊处理的语句,实在不能避免的情况下应该采用is运算符判断,而非ClassName。
在一种很特殊的情况下,is可能不能得到想要的结果,比如需要分别处理TEdit和TCoolEdit的情况,用is的话CoolEdit也会判断为TEdit,这时可以采用ClassType方法,也要胜过没有类型检测的字符串比较:
    aCoolEdit is TEdit               //True;
    aCoolEdit.ClassType = TEdit      //False;
    aCoolEdit.ClassType = TCoolEdit  //True;

上一篇:CRC算法的实现 人气:5484
下一篇:发掘ListBox的潜力(一):自动调整横向滚动条宽度 人气:5211
浏览全部Delphi的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐