本文使用一个简单实例讲述如何使用多态在Delphi中实现动态编程。
多态(Polymorphism)按字面的意思就是“多种形状”。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。更多有关多态的讲述,请参考网络资料。
“动态语言“是一种在执行期间才去发现数据类型的程序设计语言,其有点在于其优良的扩展性,主要用于创建一些需要经常更新的动态系统。本文描述的动态编程,没有动态语言的意思,但是能让Delphi程序同样具有动态扩展的能力。
以Polymorphism的字面意思来举例,要实现一个画出各种形状的程序。刚开始,可能只需要实现画矩形、正方形的功能,但是可预知以后需要画其它图形。这很自然想到使用多态来实现,可是如何实现在增加其它形状时主程序完全不用修改呢?
一、实例描述:
1. 抽象类TGeometry(几何图形),它有一个画图形的抽象方法Draw()
2. 继承抽象类的子类:TRectangle(矩形)、TSquare(正方形)等等。所有类如下图
3. Main程序无须知道子类,只通过TGeometry画出各种图形,也无须关心当前有多少子类
4. 实例程序界面如下
界面左侧图形单选按钮的数量会根据TGeometry的子类数量变化。选不同单选按钮,会调用相应的Draw()方法在右侧画图
源代码下载(使用Delphi 2010编写):>>>
二、通常情况下的实现
1. 抽象类(TGeometry)和子类(TRectangle)
2. 在主程序中使用TGeometry
这样使用的缺点是:当增加新形状时,主程序代码需要修改。究其原因,是因为“子类实例的创建”是静态写在代码中的。
接下来,想办法把子类的创建从主程序中剥离,是程序具有动态特性。
三、把形状类型从主程序中剥离
下面讲述如何逐步把“子类实例的创建”静态代码从主程序中剥离。
第一步,使用CASE语句把形状创建函数剥离
最简单的方式,就是使用case语句,根据不同形状调用不同子类的Create方法创建子类的实例。
这样DrawGeometry()被“解脱”了,可是CreateGeometry()又被“套住”了:每增加一个形状,需要增加一行代码。case语句实际上还是静态的。
第二步,消除CASE语句,实现真正的“动态”
要彻底消除“静态”,需要使用Delphi提供的动态东西,最直接的就是动态数组。如果把所有子类的形状,以及创建实例的函数都存在动态数组中,不就可以实现真正的“动态”了吗。
每增加一个子类时,都会将自己注册到Shapes和Creators中。
在本实例中,唯一剩下的没有“被动态”的是DrawGeometry()中使用的AShape变量。
四、主程序界面动态生成
界面中形状单选按钮根据已经注册的形状子类动态生成,然后插入到RadioGroup中。
到此为止,主程序中没有任何与形状子类有关的静态代码。
五、增加新的形状子类
接下来可以体验一下,如何新增形状子类而不用修改主程序。
新建一个uCircle.pas单元,在其中实现TCircle形状子类、并注册到Shapes和Creators中;然后把uCircle单元加入到项目Sdiapp中;重新编译,运行程序,在界面左侧就多了一个Circle单选按钮。