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