前 言
第一次知道Delphi並不是因為Borland公司的Delphi軟件,而是在柏拉圖的經典著作《柏拉圖對話錄》“申辯篇”中讀到了這個單詞。
A frIEnd of mine . . . went to <?XML:namespace prefix = st1 ns = "urn:schemas-microsoft-com:Office:smarttags" />Delphi and boldly asked the Oracle to tell him whether . . . there was anyone wiser than I was, and the Pythian prophetess answered that there was no one wiser . . .
Delphi和蘇格拉底的智慧
Delphi是預言之神Oracle居住之地。《柏拉圖對話錄》記載了蘇格拉底的一位朋友前往Delphi向預言女神Pythian詢問誰是最智慧的人。Pythian說沒有人比蘇格拉底更智慧。蘇格拉底深感不解,因為他發現自己身邊有很多政治家、詩人、哲學家和藝術家。難道這些“專家”和“權威”不是更有智慧嗎?自己比起他們差多了。
蘇格拉底一一拜訪了這些“專家”和“權威”,卻發現他們往往自以為是,自欺欺人,對自己不懂的東西也假裝知曉。通過拜訪,同時蘇格拉底也發現自己在許多方面知之甚少。但蘇格拉底並沒有不懂裝懂,他坦誠了自己的無知。這就是預言女神Pythian所說的真正的“智慧”。
其實這種智慧不是古希臘人最早提出來的。早在蘇格拉底之前,我國的老子就已經總結過了。《道德經》中有“知人者智,自知者明”,此之謂也。
現在,我們使用的Delphi已經是一個優秀的編程語言和軟件開發工具了。然而,面對博大精深、不斷發展的Delphi,我們在許多方面還知之甚少。可是在學習和使用Delphi時,我們是否也具備了蘇格拉底那種自知自明的態度和知所不知的智慧呢?
有許多選擇Delphi的朋友,最初的想法可能是因為Delphi功能強大,易學易用。他們甚至3個月就聲稱精通了Delphi,半年就敢獨立開發軟件。其實他們所能做的工作僅僅是控件的拖拉而已。當他們為自己的程序陶醉時,實際上是在為Delphi的精巧睿智和別人的控件所陶醉。這種Delphi程序員往往被別人戲稱為“拖拉”員。而他們卻俨然以Delphi高手自居。
也有許多放棄Delphi的朋友,最初的想法可能是因為覺得Delphi只是一個類似VB的RAD工具。在他們看來Delphi就是控件編程,無法像C++或Java那樣真正實現OOP。他們懷疑Delphi是不是具備面向對象編程語言的特性、能不能實現多態、模式等面向對象的技術。在他們眼裡只有使用C++或Java的人才是真正的高手。
那麼,什麼是真正的高手,怎樣才能成為一個高手呢?
論“器”與“氣”
首先讓我們來看一看什麼是武林高手,或許我們能夠從中得到啟發。
凡是喜愛武功或武俠小說的人都知道,修煉武功分為外練和內修兩種途徑。外練拳腳、兵器,拳腳的招式和兵器的好壞是關鍵;內修真氣,練精化氣、練神還虛是根本。這兩種修煉方法的最大差別在於時間和功力的函數關系上,如圖 1所示。通俗地講,頭3年,練外功的可以輕易打敗練內功的;第10年,雙方只能打個平手;15年後,無論你如何練外功都不是練內功的對手。20年後,內功高手天下無敵。其中的道理正是在於 “器”和 “氣”的辯證關系。
“器”為有形之物,刀槍劍戟,皆為有形之器。外練武功,離不開這些有形之器,練功即為練兵器。所以使槍弄劍的武林高手往往依賴於兵器的好壞。
“氣”為的無形之質,一切智慧、法力、思想皆為無形之質。內修氣功,離不開這些無形之質,練功即為練氣。所以真正的武林高手往往無需依賴於特定的兵器,對於他們而言,任何有形之物皆可隨氣所運,擬為兵器。一折扇,一拂塵在其手中威力不亞於名槍好劍,是得氣所致也。
圖 1兩種修煉方法的時間和功力函數圖
在軟件開發中,編程工具是“器”,編程思想是“氣”。
編程之器中,易用之器如VB、PB;難用之器如匯編、C++;古老之器如FORTRAN、COBOL;時尚之器如Java、C#。
編程思想中,又有面向對象和面向過程之分,它們既是世界觀又是方法論。前者反映的是人對客觀對象的思維方式,後者反映的是機器對指令的思維方式。在軟件開發的不斷實踐中,前者的優越性已經得到不斷的體現和證實。
掌握面向對象的編程思想如同獲得練氣的真谛。它的重要性往往勝過了對編程語言的選擇!
有人即使選擇了面向對象的利器,也無法成為真正的高手。因為他看重的是“器”的好壞,忽略的是“氣”的修煉。
實際上“一個系統或語言是不是面向對象的並不重要,重要的是怎樣才能是面向對象的以及用什麼辦法實現相關的好處”。(《面向對象方法:原理與實踐》機械工業出版社2003年3月)
練器雖易,但難成高手。練氣雖好,但見效緩慢,寂寞難耐,非一般常人可以明心見性,直取大道。所以很多武林高手都是先練器、後練氣;內外兼修,終成正果。
對於初入武林的新手,他們需要借助兵器的威力,以補內力之不足,器的好壞往往很重要。但隨著武功的增加,內力的勃發,對器的依賴性應該減小。《神雕俠侶》楊過練劍,起步初學時好使利劍,谙悉劍法後喜用鈍劍,內功純熟後樹枝亦當劍。所以對於真正的高手而言,劍器的好壞往往並不重要。
同樣,軟件高手的成長也有這樣的過程。初學編程需要選擇好的語言,這樣可以取得事半功倍的效果,同時激發興趣,增強信心。一旦熟悉了一種語言之後,應以此為契機進而掌握面向對象編程思想。這時你熟悉的不再是語言本身的語法、函數、類庫,而是綁定、多態、模式等思維方法,然後觸類旁通,再學其他面向對象語言也不難。苦練內功,勇於實踐,最終成功的真正的軟件高手,是不受編程語言限制的。他們可能比較熟悉一種開發工具,但那也只是承載他們大道無形之氣的器具。他們虛心好學,善於總結。他們的思想、方法、模式甚至哲學,既超越了編程語言,又可以指導編程語言的實踐。
Delphi為軟件高手的成長提供了內外兼修的捷徑。學練Delphi,既可用其RAD之長,控件之利,初學起步,迅速擊敗對手;學練Delphi,也能以其OOP之能,VCL之強,培根固本,成就不敗之功。
威震四海的華山劍派曾分為“劍宗”和“氣宗”,前者只練器,講招式;後者兼練氣,重築基。
學習Delphi好比修煉華山劍法,走RAD之路是 “劍宗”,從OOP之道是“氣宗”。前者喜用控件,看中奇技淫巧;後者好為對象,熱衷方法模式。前者追求速成,後者志存高遠。
我認為,無論是為RAD而選擇Delphi還是因OOP而放棄Delphi的朋友都沒有真正了解Delphi。Delphi是一個不錯的RAD開發軟件,可是不學OOP,不深入VCL就很難成為真正的高手。同樣,Delphi是一個地道的OOP編程工具,結合Delphi強大的RAD和高效的編譯器,可以比其他OOP語言有更多的優勢和更高的效率。如果能打破門戶之見,“器”“氣”同練,內外兼修,我相信Delphi程序員不難從一個RAD快手成長為OOP高手,最終笑傲江湖,縱橫四海。
面向對象編程思想和大道無形之氣
前面我簡單討論了“器”與“氣”的辯證關系。在編程中,修持內功、提高內力的關鍵之一在於掌握面向對象編程思想。實際上,我更認為面向對象編程思想才最合大道無形之真氣的妙處。
為什麼這麼講?“古之大化者,乃與無形俱生”(《鬼谷子》反應第二),氣的奧妙首先在於它的“大化”。大化者,天地之大造化也,集一切創造和變化之能。面向對象的編程思想具備了這種特質。
老子曰“無名天地之始,有名萬物之母”,無名是無以名狀,無法定義的意思。所謂面向對象的思維方式,最奧妙之處在於如何從“無名”中識別和定義對象、如何從“有名”中構造和使用對象。
對於軟件開發人員來說,認識客觀實體的過程、對用戶需求進行分析和設計的過程,就是發現和界定對象的過程,是從無名到有名的過程。然而這裡的對象又不同於面向過程中的變量或函數,對象是由類創建的,類是概念的抽象,是可以定義的“有名”,是對象之母。
於是乎,太極生兩儀,兩儀生八卦,通過類的繼承和派生,萬物始生,系統構成。
即使作為面向對象編程工具的“器”,也體現和承載了面向對象的編程思想之“氣”。
號稱“萬古丹經王”的內功練氣經典之作《周易參同契》開篇第一句話就是“乾坤者,易之門戶,眾卦之父母。坎離匡郭,運毂正軸,牝牡四卦,以為橐籥。”
從軟件開發的角度來理解,面向對象的編程工具雖然提供了構建無窮種軟件系統的可能性,但這種無限性卻是建立在自身類庫的有限框架之中。無論是Delphi的VCL,還是Java的類庫,或是.Net框架,無一不是建立在這樣一個類似於周易八卦的架構之中。“易有太極,太極生兩儀,兩儀生四象,四象生八卦” ,這樣的結構完美無瑕,有著無窮的創造力。
太極是Delphi中的TObject,它是構建系統的原子,它是所有類的祖先,它具有所有類的基本特征。在Delphi的編程世界中,根類TObject生持久對象類TPersistent,持久對象類TPersistent生組件對象類TComponent,進而為開發應用程序提供了豐富的控件和強大的功能。
然而類庫的結構框架不僅僅是給我們可以作為“器用”的組件,更重要的是這種結構通過類之間的關系和相關作用,實現了“氣”的構造和變化,體現出面向對象編程思想的精髓。為我們創建自己的系統提供了絕好的示范。
氣的奧妙其次在於它的“生於無形”。無形意味著它的自由性、開放性、適應性。在面向對象編程思想中處處充滿著 “氣”的這種大道無形的智慧。
比如,面向編程對象中的多態性可以使程序員撰寫更加通用的、更加開放的程序。程序員可以為Vehicle對象編寫一個純虛抽象方法Stop(),這樣的通用Stop()方法與駕駛什麼車無關。程序員可以讓派生類去操心如何完成stop()方法,而繼續在更高的抽象級別上編寫自己的通用過程。即使Car對象的stop()方法與Bicycle對象的stop()方法完全不一樣,程序員可以也可以使用Vehicle.stop(),多態性可以讓創建的對象自動知道哪一個合適的方法將被調用。這就使程序具備了“氣”的開放性和適應性。
練氣功中講究“上德無為,不以察求。下德為之,其用不休。”(《周易參同契》)
在面向對象編程思想中,“上德”是晚綁定的純虛抽象方法、是以不變應萬變的對象接口,它是對事物的高度抽象、是形而上學。“上德無為”是說在抽象層次,通過無為來體現編程“虛”的一面,因為這時還無法確定實際使用的真正對象(可能是Car對象也可能是Bicycle對象,更可能是以後發明的新交通工具對象),“不以察求”要求我們跳出具體需求的約束,不去考慮具體的實現代碼。所以純虛抽象方法或對象接口中是沒有任何代碼實現的。
在面向對象編程思想中,“下德”是對純虛抽象方法的覆蓋、是對對象接口的實現。“下德為之”,提供了真正的代碼實現。“其用不休”,滿足了不斷變化的需求。
多態性使得程序員在以後不費多大力氣就可以派生對象,實現程序。假設程序員在為Car和Bicycle構建應用程序,並不知道還存在Truck,但這並不要緊。程序員可以為繼承Vehicle類的Car和Bicycle類撰寫覆蓋stop()的方法。這樣,在程序中只要把創建的Car和Bicycle對象轉型為Vehicle的類型,使用Vehicle的stop()方法,就可以讓Car和Bicycle對象動態綁定符合自己要求的stop()方法。即使後來新增了Truck對象,仍然是調用Vehicle的stop()方法,並不需要進一步改動程序。
“物有自然,事有合離。有近而不可見,有遠而可知。近而不可見者,不察其辭也;遠而可知者,反往以驗來也。” (《鬼谷子》抵戲第四)
雖然客觀事物是復雜,用戶需求是變化的,但是其中也有一定的內在規律。
近而不可見者,只看眼前的具體功能實現,不察事物的一般發展規律,心中只有孤立的數據和機械的流程,一旦“事有合離”,則措手不及,難以應對。這樣的編程是靜態的、機械的、難以維護和擴展的。
遠而可知者,善於發現規律,重視代碼重用,眼中盡是有機的對象和和諧的關系,即使需求改變,也能從容應對,游刃有余。這樣的編程是動態的、靈活的、可維護和可擴展的。
Paul Kimmel在《Delphi6應用開發指南》中說“以非面向對象的方法去使用面向對象工具是一個錯誤。使用Delphi編寫結構化程序可以很快地到達beta版……你的程序可能永遠脫離不了beta版。迅速得到錯誤的答案,仍然是錯誤的。”
同樣是使用Delphi,如果沒有面向對象的編程思想,好比“不察其辭”,最終仍然是“近而不可見”,難以開發出優秀的系統。唯有潛心苦練,悉心總結,掌握面向對象編程思想的博大精深,才能運“氣”自如,“反往以驗來也”,最終達到“遠而可知”的境界。
關於本書
從第一個真正面向對象的語言Smalltalk(1972年)出現至今已經有30多年的歷史了。然而書店中充斥著面向對象編程的書籍大都是C++和Java,似乎面向對象的語言僅有這兩種,而實際上真正的面向對象語言卻有4個基本分支,近20種之多。由於Delphi面向對象編程的書籍很少,不少程序員為了學習OOP,不得不放棄Delphi。這真是Delphi的一大悲哀。當我讀到Bruce Eckel的《Thinking in Java》,就感歎過為什麼就沒有這樣的Delphi大作呢?
其實,Delphi 系出名門,她是Borland公司在Object Pascal基礎上開發的。現在,Borland公司從Delphi7開始使用Delphi language來取代Object Pascal叫法[1]。Delphi 在OOP方面實際上並不比C++和Java遜色,這一點讀者可以參見本書附錄“面向對象編程語言比較: Java、C++和Delphi”。
為此,我一直打算寫一本Delphi面向對象編程的書,總結自己在Delphi面向對象編程方面的學習體會和實踐經驗。然而這是一項難度不小的工作,全書從構思到下筆花費了很長的時間,直到今年5月才算正式完稿。剛巧今年也是Borland創建20周年,作為Borland產品Delphi的用戶,拙作的出版也算是對此的紀念。
這是一本純粹討論Delphi面向對象編程的書,面向對象不是本書的時髦點綴,而是這本書的核心和全部。
本書自第1章“建立面向對象的新思維”開始就試圖從面向對象編程的歷史和現狀入手,闡述面向對象編程思想的起源發展和基本觀念,以及面向對象建模方法和UML的應用。這一章是為了幫助讀者建立面向對象的基本概念,了解面向對象的思維方法。
第2章“Delphi對象模型”介紹了Delphi面向對象編程的基礎知識及其對象模型結構體系。
第3章“理解對象”從對象的本質、生死、關系三方面深入討論了對象的內部機制、生命周期、相互作用,為讀者了解和掌握對象打下了基礎。
第4章“使用對象”講解了在Delphi面向對象編程中如何高效使用對象。這裡重點討論了界面對象、組件對象、對象集和對象參數的使用方法和技巧,並對VCL組件使用和開發中的常見問題進行了深入思考。
第5章“深入多態”介紹了多態的概念及其在編程中的應用。其中通過大量的實例講解了重載和覆蓋、虛方法與動態方法、抽象類和抽象方法、類的類型轉換等重要概念和思維方法。
第6章“剖析接口”全面介紹了對象接口的編程知識和應用技巧。闡述了接口在實現動態綁定和多重繼承方面的重要作用,演示了接口在面向對象編程中的實際用法。
第7章“研究封裝”闡明了封裝在面向對象編程中的重要意義和應用原則,並分別從邏輯上的封裝和物理上的封裝來進一步討論封裝的實現方法和應用技巧。
第8章“實現界面和業務的分離”將面向對象編程應用到一個新的高度。這一章通過界面和業務分離的演化實例,講解了如何利用面向對象的設計將一個桌面程序進化到分布式多層系統。並接合Delphi的最新Web技術,介紹了如何用Web Service封裝業務對象,用Web Form封裝界面對象,用新技術封裝舊對象,從而實現跨平台的應用。
最後本書第9和10章的“深入淺出VCL”,研究了VCL的內部機制,並剖析了VCL重要類系的對象用法,為渴望深入提高編程水平的讀者提供了參考。
從本書的組成結構上看可以劃分成5大部分。
第1部分,全書的前兩章是Delphi面向對象編程的入門。已經掌握面向對象基本概念並有Delphi