本文使用一個簡單實例講述如何使用多態在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單選按鈕。