首先
我们知道多态是面向对象的三大特性之一
所谓多态
其思想就是
对于不同的具体类型
我们可以通过相同的抽象接口进行访问
而不必关系具体类型的实现细节
就像下达通知
所有员工明天
点在人民广场集合
并不需要具体通知每个住在不同位置的人应该几点出发
走什么路线
因为这是具体的人的责任
而非通知下达者的责任
所以
在写到需要判断ClassName进行分别处理的时候
首先应该想到的处理方式是在父类中增加接口
通过子类override完成
如下面改变把图形大小的代码
for i := to 图形列表Count do
begin
图形 := 图形列表[i];
if 图形ClassName = 长方形 then
begin
长方形(图形)长 := 长方形(图形)长 * ;
长方形(图形)宽 := 长方形(图形)宽 * ;
end
else if 图形ClassName = 圆形 then
begin
圆形(图形)半径 := 长方形(图形)半径 * ;
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 := to 图形列表Count do
begin
图形 := 图形列表[i];
图形ChangeSize();
end;
这样代码的意图清晰了很多
当然在很多时候出现判断ClassName的情况下并不能采用上边的解决方法比如遍历Form的Cotrols并对不同的控件进行分别初试化我们不可能去TControl中增加初始化方法只有采用判别具体子类类型那么这时我推荐采用is运算符而非直接比较ClassName
is的用法语句 aObject is TForm 在不同的aObject的类型情况下结果如下
aObject是TObject结果为假
aObject是TForm结果为真
aObject是TForm结果为真
aObject是TEdit结果为假
aObject是nil结果为假
从上面示例可以看到采用is的一个优点is可以判断是否子类的情况比如我们在初始化控件的时候根据是TImage还是TEdit作不同的初始化通过is判断处理将来也许会采用TCoolEdit来美化界面那么这段代码不需要更改因为一个TCoolEdit是一个TEdit而如果采用ClassName那么必须更改为子类的名字才行
其次如果被判断的对象有可能为空使用ClassName判断必须先判断对象是否赋值否则就会出现内存访问错误判断代表必须写为if Assigned(aObject) and aObjectClassName = TClass而采用is只需要写为if aObject is TClass
最后一个不采用ClassName作为判定的原因是ClassName只是用来描述一个类的属性字符串比较不能在编译期获得检查如果存在拼写错误或是大小写问题代码都会出现逻辑错误而这种错误只有在运行期运行到这一语句的时候才会被发现
if aControlClassName = TEidt then //只有在你注意到Edit没有初试化时才会来检查这段代码
if aControl is TEidt then //无法编译通过
综合上面所述在需要判定一个对象的具体类型时首先应该考虑通过多态处理避免这种分别特殊处理的语句实在不能避免的情况下应该采用is运算符判断而非ClassName
在一种很特殊的情况下is可能不能得到想要的结果比如需要分别处理TEdit和TCoolEdit的情况用is的话CoolEdit也会判断为TEdit这时可以采用ClassType方法也要胜过没有类型检测的字符串比较
aCoolEdit is TEdit //True;
aCoolEditClassType = TEdit//False;
aCoolEditClassType = TCoolEdit//True;