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

本文探讨了面向对象编程中多态特性的应用,通过实例展示了如何利用多态简化代码并提高可维护性。同时对比了使用is运算符与直接比较ClassName进行类型判断的优劣。

首先,我们知道多态是面向对象的三大特性之一。所谓多态,其思想就是,对于不同的具体类型,我们可以通过相同的抽象接口进行访问,而不必关系具体类型的实现细节。就像下达通知:所有员工明天9点在人民广场集合。并不需要具体通知每个住在不同位置的人应该几点出发,走什么路线,因为这是具体的人的责任,而非通知下达者的责任。所以,在写到需要判断ClassName进行分别处理的时候,首先应该想到的处理方式是在父类中增加接口,通过子类override完成。如下面改变把图形大小的代码:

2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 


    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;  

 

【完美复现】面向配电网韧性提升的移动储能预布局与动态调度策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于IEEE33节点的配电网韧性提升方法,重点研究了移动储能系统的预布局与动态调度策略。通过Matlab代码实现,提出了一种结合预配置和动态调度的两阶段优化模型,旨在应对电网故障或极端事件时快速恢复供电能力。文中采用了多种智能优化算法(如PSO、MPSO、TACPSO、SOA、GA等)进行对比分析,验证所提策略的有效性和优越性。研究不仅关注移动储能单元的初始部署位置,还深入探讨其在故障发生后的动态路径规划与电力支援过程,从而全面提升配电网的韧性水平。; 适合人群:具备电力系统基础知识和Matlab编程能力的研究生、科研人员及从事智能电网、能源系统优化等相关领域的工程技术人员。; 使用场景及目标:①用于科研复现,特别是IEEE顶刊或SCI一区论文中关于配电网韧性、应急电源调度的研究;②支撑电力系统在灾害或故障条件下的恢复力优化设计,提升实际电网应对突发事件的能力;③为移动储能系统在智能配电网中的应用提供理论依据和技术支持。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析,重点关注目标函数建模、约束条件设置以及智能算法的实现细节。同时推荐参考文中提及的MPS预配置与动态调度上下两部分,系统掌握完整的技术路线,并可通过替换不同算法或测试系统进一步拓展研究。
先看效果: https://pan.quark.cn/s/3756295eddc9 在C#软件开发过程中,DateTimePicker组件被视为一种常见且关键的构成部分,它为用户提供了图形化的途径来选取日期与时间。 此类控件多应用于需要用户输入日期或时间数据的场景,例如日程管理、订单管理或时间记录等情境。 针对这一主题,我们将细致研究DateTimePicker的操作方法、具备的功能以及相关的C#编程理念。 DateTimePicker控件是由.NET Framework所支持的一种界面组件,适用于在Windows Forms应用程序中部署。 在构建阶段,程序员能够通过调整属性来设定其视觉形态及运作模式,诸如设定日期的显示格式、是否展现时间选项、预设的初始值等。 在执行阶段,用户能够通过点击日历图标的下拉列表来选定日期,或是在文本区域直接键入日期信息,随后按下Tab键或回车键以确认所选定的内容。 在C#语言中,DateTime结构是处理日期与时间数据的核心,而DateTimePicker控件的值则表现为DateTime类型的实例。 用户能够借助`Value`属性来读取或设定用户所选择的日期与时间。 例如,以下代码片段展示了如何为DateTimePicker设定初始的日期值:```csharpDateTimePicker dateTimePicker = new DateTimePicker();dateTimePicker.Value = DateTime.Now;```再者,DateTimePicker控件还内置了事件响应机制,比如`ValueChanged`事件,当用户修改日期或时间时会自动激活。 开发者可以注册该事件以执行特定的功能,例如进行输入验证或更新关联的数据:``...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值