Delphi 中面向對象編程之我見(jiàn)
原文引用自
http://940801.cndev.net/mydoc/delphioop.html 面向對象的編程技術(shù)(OOP)提出來(lái)也有些年頭了,開(kāi)發(fā)大型軟件的時(shí)候采用面向對象的編程技術(shù)可以縮短程序的開(kāi)發(fā)周期,提高程序的可讀性,易調試性,同時(shí)也就相應的提高了程序的可維護性,而對大型軟件而言,可維護性是保證其生命力的一個(gè)極為重要的指標。
不知大家注意到?jīng)]有,可視化程度很高的編程語(yǔ)言在采用面向對象的編程技術(shù)上很難處理。例如 VB,4.0 基本不支持面向對象的編程,5.0 好一些,但微軟也只敢說(shuō)在面向對象的編程上 5.0 比 4.0 好得多,而不敢說(shuō) 5.0 支持完全的面向對象的編程(6.0 以后的版本我沒(méi)用過(guò),不知道情況,如果能支持,也是 VB 愛(ài)好者的福音了)。這大概就是人們常說(shuō)的不用 VB 做大型程序的重要原因之一吧。 我不知 Delphi 是從什么版本開(kāi)始提供面向對象編程支持的,但我從 VB 5.0 轉到 Delphi 4.0,除了項目要求外,這是最重要的原因了。
由于 Delphi 除了支持面向對象的編程外,也支持一般的面向過(guò)程的編程,而且因為其可視化技術(shù)的運用,很多人(包括我)很容易就偏離了面向對象的方向。實(shí)際上,我覺(jué)得要實(shí)現面向對象的編程也不難,因為 Delphi 給您的全都是對象了,您只要在編程的時(shí)候注意自己的代碼就可以了。下面是我對在 Delphi 中采用面向對象技術(shù)的一些體會(huì ):
1.用全局對象來(lái)代替全局變量
習慣了面向過(guò)程編程的程序員在這點(diǎn)上很容易犯錯,而且這一點(diǎn)相對來(lái)說(shuō)也比較難掌握。實(shí)際上,全局變量也是面向過(guò)程編程技術(shù)的一個(gè)很大的缺陷,難跟蹤,難調試,也就難維護。
為什么要用對象而不是變量呢?對象可以封裝對變量的操作,任何對該變量的操作都必須通過(guò)調用對象的方法來(lái)完成,我們可以在操作該變量的方法中設置斷點(diǎn)來(lái)調試,這就解決了前面所提到的 3 個(gè)難點(diǎn)(難跟蹤、難調試、難維護)。
舉個(gè)常見(jiàn)的例子(也許并不能最大限度的反映這個(gè)問(wèn)題):讓您做一個(gè) IE,對于 Internet Options,您打算怎樣處理?
根據以上的觀(guān)點(diǎn),我的想法是寫(xiě)一個(gè) TDefaultIni 類(lèi),這個(gè)類(lèi)負責 Options 中各項設置的保存,讀取。Options window 和別的需要操作其中設置的對象都通過(guò)這個(gè)類(lèi)來(lái)進(jìn)行處理。它們不需要知道這些設置是保存在那兒和怎樣保存的,這樣就實(shí)現了對數據的封裝。您可以定義一個(gè) TDefaultIni 類(lèi)的實(shí)例作為全局對象隨時(shí)可以程序中通過(guò)訪(fǎng)問(wèn)它來(lái)獲取或者修改設置。當然,因為這些設置是保存在存儲器中可以隨時(shí)讀取的,您也可以只在需要的時(shí)候創(chuàng )建一個(gè) TDefaultIni 對象來(lái)完成您的功能。
2.對象之間交換數據,盡可能的使用屬性而不是變量
為什么要用屬性而不是變量呢?對數據的操作可以通過(guò)屬性的方法進(jìn)行封裝,一旦以后對象內部的數據結構發(fā)生了變化,只要我們提供的屬性接口不變,對程序別的部分的影響就能減小到最小。例如 Form 之間通過(guò)屬性來(lái)交換數據。以后因為某個(gè)原因您得將原來(lái)用數組實(shí)現的東西改為用鏈表實(shí)現,只要您的屬性接口仍然是數組,那對別的對象就幾乎沒(méi)有影響。又比如您原來(lái)用 TEdit 來(lái)實(shí)現的東西用 TComboBox 來(lái)實(shí)現了,您只需簡(jiǎn)單的修改屬性的 read,write 方法,別的對象就根本不需要修改。
3.合理的安排對象的方法
我直接舉例來(lái)說(shuō)明這個(gè)問(wèn)題,例如在連接數據庫的時(shí)候,您是在主 Form 中設置好 TDataModule 中 TDatabase 的 AliasName 和 Params,然后用 DataModule.Database.Open 來(lái)連接呢,還是寫(xiě)一個(gè) TDataModule.ConnectToDatabase 方法,將 AliasName 和 Params 作為 TDataModule 的屬性,而在主 Form 中調用這個(gè)方法來(lái)連接呢?從理論上來(lái)講,兩種方法都是面向對象的。也許很多人不能體會(huì )到后一種方法的優(yōu)越性,想象一下如果數據庫發(fā)生了變化,以前只有 Sql Server,現在還需考慮 Oracle。后一種方法將會(huì )使您的應對輕松的多,尤其是您在主 Form 中有好幾處地方需要連接數據庫的時(shí)候。
4.合理的安排您的對象
一個(gè)問(wèn)題該由幾個(gè)對象來(lái)解決,每個(gè)對象實(shí)現什么功能,它們之間是什么聯(lián)系?這是面向對象編程永恒的問(wèn)題,Delphi 中這個(gè)問(wèn)題怎么處理呢?在此我就和 Form 有關(guān)的問(wèn)題和大家討論一下吧,先舉一個(gè)例子:寫(xiě)一個(gè)將 IE 中的收藏夾導入到數據庫中的程序,您會(huì )怎樣來(lái)安排您的對象呢?這個(gè)問(wèn)題并不復雜,一個(gè) Form 就能解決問(wèn)題了,也許為了數據庫管理比較方便,再加上一個(gè) DataModule,Form 負責讀入收藏夾,將之顯示在 TreeView 中,用戶(hù)可以選擇 TreeView 的節點(diǎn)(即收藏夾)導入數據庫。也許您的程序剛做好,老板又要求對 NetScape 的 BookMark 也完成同樣的功能。怎么樣?您的改動(dòng)量有多大?如果您以前使用的是兩個(gè)對象來(lái)完成上面討論的一個(gè) Form 的功能,一個(gè)對象負責將收藏夾的數據導入到 TreeView 中,而 Form 對象只完成對 TreeView 的操作,您就會(huì )發(fā)現您的改動(dòng)是很輕松的。由此我的建議是 Form 對象只完成對界面的操作,對于具體的數據結構,由我們自己寫(xiě)的與數據結構相關(guān)的對象去完成。
5.不要在兩個(gè)同級的子 Form 之間交換數據
在 Delphi 中很容易犯這個(gè)錯誤,這樣做是很危險的,因為很有可能您認為存在的 Form 被關(guān)閉了或者干脆就沒(méi)有打開(kāi)過(guò),而且這樣做最大的壞處是程序晦澀難懂。解決的辦法之一是可以通過(guò)它們的父 Form 來(lái)交換數據,例如父 Form 中取得 A 子 Form 的屬性值,根據這些值來(lái)設置 B 子 Form 的屬性值。
面向對象的編程技術(shù)絕不只是應用在大型軟件的開(kāi)發(fā)上,實(shí)際上,小型程序采用面向對象的技術(shù)開(kāi)發(fā)對于今后的擴展和移植(即是只是部分功能的移植)是很有幫助的。希望我的這篇文章能起到一個(gè)拋磚引玉的作用,歡迎大家和我討論。