一個月學會VC++2010 4.細說對象之香艷旖旎
作為程序員,我們其實生活在一個荒誕的空間。每次看到白發蒼蒼的教授,很認真很莊重的說:“面向對象灰常灰常重要”的時候,我都完全忍不住要笑出來。我們用所有的詞,第一個反映怕是從字面上來理解。對象,準備結婚的異性,面,你的臉,向,朝著她。你的臉朝著異性,接下來會發生什么,外交部曰:“那是他們的內政,各國無權干涉”。教授究竟在教我們什么?
所以在這個眾牛奔騰的圈子里,好象每個人都生活在這樣香艷的語境中。隨隨便便拉頭牛過來,他估計能夠告訴你面向對象是多么的重要、多么的牛,你不會面向對象你都不好意思摸著鍵盤。你要問他什么是面向對象,他會告訴你:“嗯,不是寫個類就完了,這是一種思想,一種……”,然后還是歸于那三個指頭、五個字,“博大精深”。
臺灣對object的翻譯有些不同,相對來說更合理一些:“物件”,面向對象被翻譯成“物件導向”。世易時移,這兩片土地的語言都在漸漸分化,作為反面角色的我們,早已經成為文化的沙漠和馬某人的余孽。那是題外話,說正題。如果用今天的漢語,準確的翻譯,我猜測只有一個詞:“東西”,“面向對象”不妨翻譯成“站在東西的角度”。
漢語原本是比較模糊的語言,生造一些詞匯,或者給一些詞匯賦予完全不一樣的含義,這是最糟糕的情形。之所以最糟糕,因為我一向所強調的“簡單”,首當其沖的就是“理解的簡單”。站在東西的角度,這個小學生都能夠理解,而面向對象,其他專業的博士生都無法理解。之所以會出現這類翻譯,是因為語言和技術都精通,而且具備專業翻譯技巧的人,幾乎沒有。最明顯的例子,大家可以看看微軟的Team Fundation Server,里面的ms agile模版,其中優先級,翻譯成“堆棧級別”;然后“產品積壓工作”、“用戶情景”、“迭代”、“情景點”,看看,哪里象是正常人說的話?
面向對象,也令我想起一句廣為流傳的小資名言:“面朝大海,春暖花開”。當然你略微動動腦子,這實際是個病句。面朝大海的時候,你看到的往往是一片藍色,如果你的身體這時候感覺到溫暖,倒也正常,同一瞬間你的思維居然意識到是在春天,這就是不專心了----比較恐怖的是,你的眼睛居然在海面上發現了鮮花正在開放,唉,一段時間好象不說這句話都算是沒素質,所以斷章取義是不行的,這是海子的一首很平常的詩,這句話前面還有一句是“我有一所房子”,當然,是這房子面朝大海,是這房子春暖花開。
然后第一句是:“從明天起,做一個幸福的人”,兩個月之后,詩人臥軌自殺,成就了杯具般的凄美。我一直不太敢說:“從明天起”如何如何,也知道幸福的人不是你想做就能做的。必須給自己保證,做一個活人,哪怕是垃圾般生存,這個比幸福重要。
我們可以回憶一下,所有教科書,都將“面向對象”概念和如何用面向對象的方式設計割裂開來,講概念通常是一章的內容,特別精細的還分成多章,將封裝、繼承、多態拿出來逐一講解。通過漫長的歲月之后,恐怕很多人還是不理解,為什么?黑板、講解、瞌睡的三部曲而已講解面向對象的概念,仿佛是入門的東西,講解面向對象的思考方法,則是需求分析、設計模式等等看起來高端的范疇。
其實,還是那句話,哪里有那么復雜?我國專業人士,基本上個個都是老中醫,仿佛不磨你幾十年你就能夠做好事情,那就談不上博大精深。
我們就拿他們常見的場景,用我們的語言來剖析一下。假設我們要做一個模擬的生物世界游戲,有樹、草、花、蘋果樹,有鳥、有魚、也有狗狗和牛牛。
那么我們看到了什么?就是這些“東西”,嗯,他們說的對象:樹、草、鳥、魚等等。
他們說的繼承是什么?這些東西是有分類的,分類是通過相同的特性、相同的行為來劃定的。分類的原因是什么?不要重復。這里首先是生物類,哪些特性?生或者死、壽命。哪些行為,比如“生長”。然后動物和植物類,可以繼承自生物類,而樹可以繼承自植物類,魚可以繼承自動物類。
這樣,共同的特性和行為,往往不需要每個類都要重復編寫。看清了嗎?實際上來源于一種樹形分類的方式,目的是令相同的代碼不要重復編寫,是一種提高效率的手段。
類對對象的區別:我們用一類東西和一群東西來表達,比如一種叫做魚的動物,我們用class 魚{}來定義,實際上是抽象所有魚的特性和行為。游戲中要呈現三頭魚,兩條魚合作生下了很多魚籽,然后又產生很多小魚,那就是一群魚,什么意思的:“創建了具體的魚”,這就是所謂的實例化,常常有人鼻孔朝天的說:“你知道對象和類的區別嗎?”,就象說:“你知道VC和C++的區別嗎?”一樣,其實是普通初中生都能夠輕易理解的東西。
再說說封裝:如果我們著手寫這個游戲,早期的方法,顯然是寫一大堆的函數,會有“魚游動”、“狗跑動”,然后一大堆數組,描述存在多個各種類型的動物、植物。這時候程序員象上帝一樣,每一個細節都由他的代碼所控制----這意味著他獨自面對復雜的世界,編程是不是很麻煩?現在,我們將這些東西找出來,對于魚、狗狗,他們的特性和行為都看成是一類東西,也就是類。一個名字:狗狗;一堆特性、一堆行為,這樣我們的代碼,就將和狗狗相關的一切包裹在一起。程序員就能站在更高層面思考問題:比如他可以先不實現這些類,這個場景需要N只狗狗、兩頭牛牛,創建相應數量的實例就行了,他們的移動、生長、繁殖不需要在這個層面考慮。
所以封裝首先是一種良好的代碼組織方式,能夠簡化復雜性、有利于團隊合作:比如游戲中魚居然飛起來了,去找寫魚這個東西的程序員;狗狗竟然不會動了,去找寫狗狗的程序員;牛居然只有3厘米高,嗯,去找博客園的牛牛們。
至于多態,則是一種彌補方式,樹形分類的思維,也就是劃分層次的思維,雖然效能要高過線性思維,但也存在問題:比如動物有“移動”的行為,但鳥在飛、牛在爬、狗在跳,行為的方式不同。那么,我們只約定動物這“類”東西有個虛方法“移動”,讓它從一個點到另一個點,而鳥可以重寫這個需方法,可以既保持動物類在不同點之間的移動過程,又增加自己移動的姿態,方便界面上呈現出來。
大體上就這么些內容,面對任何問題,找出里面所有的東西,歸納這些東西具備的共同特征和行為,在抽象的層面尋求繼承、多態從而從整體上減少代碼量的可能。這就是面向對象的思考方法和實際的編程方法。東西不一定是業務上的,比如“線程”也是一種東西,操作系統范疇的。
那么針對導入日線文件這項功能,我們站在東西的角度,怎樣做?
首先,我們知道要做什么:用戶從其它行情軟件下載日線數據;用戶選擇這些日線數據;系統識別這些日線數據;系統將這些日線數據保存在自己的數據庫中。
這是主要的流程。
另外:因為存在對這些日線數據進行預處理的工作,用戶要求只能增加系統中最新交易日之后的數據,這就存在著當某日沒有;因為數據量大,導入過程等待的時間比較長,而且界面僵死不能做其他事情,因此需要隨時告知導入進度,同時使用后臺線程導入。因為用戶選擇文件很可能有誤操作選中了不是我們采納格式的文件,因此需要有文件格式的合法性檢查。因為用戶對行情數據的利用有大量查詢要求,因此要建立相應的索引以突出查詢性能,但這與導入性能沖突,因此要做好權衡,并比較禁止索引--導入--重建索引和直接導入之間的性能差異。
那么上面就是這項功能的主要描述,請注意我稱它為“功能”,這是人話,不是“用例”、“用戶場景”、“故事”。
我們首先看看,這里面有哪些類型的東西?
純業務角度:用戶、其他行情軟件、行情文件、日線、數據庫。其中沒有對用戶和其他行情軟件的要求。
非業務角度:線程。
因此我們將用三個類來體現業務因素:日線類Quote,表達一只股票一天的日線,行情文件類QuoteFile,識別行情文件格式、轉換成日線的集合,數據庫類QuoteDB,對應數據庫的日線表格。至于非業務對象,線程,則編程語言已經提供了足夠的支持。
其他如對話框、界面設計是另一個范疇的東西,當然,你看到的仍然是一系列非業務類型的類和對象。有時候我覺得又好氣又好笑,不知怎么,那么多人覺得MFC是怎樣的復雜、不花費幾十年讀它的源代碼則不足以平民憤,那就是菜鳥、那就不能做500萬行代碼的程序。我真無法想象500萬行的VC程序是干什么的,但是,站在所謂面向對象的立場,微軟這個MFC不就是已經設計好的一串類嗎,它們組合起來幫助你完成日常的界面呈現、互動工作。你一定要閱讀其源代碼,那就是不尊重微軟封裝的能力、質疑微軟做的產品的可用性和簡單性了。相對來說:你簡直是在說MFC是一群菜鳥玩出來的,連最起碼的封裝都顯得濫竽充數。在團隊中,你會仔細閱讀其他同事寫好的類嗎?對MFC,你也可以理解成其他同事寫好的類,而且是文檔非常豐富的、遠超出我們那種應付方式的類庫,還是克制一下探究細節的沖動吧。
在你開始編程之前,這些東西大約需要一個小時甚至更短的時間就能弄清楚,忽略這個步驟往往會造成整編程過程的雜亂無章,站在東西的角度,也就是面向對象的思維方式之所以重要的原因。 這一節的主題是“誰說對象不是東西?”,起因是有牛認為多數程序員缺乏面向對象思維、算法和數據結構的知識,我不太認同。事實上,實際的編程過程中,抽象類甚至接口、繼承這些出現的機率是非常小的,多數的時候大家接觸最多的不過是封裝特性。而算法和數據結構固然重要,但也僅僅是理解的問題,只有極少數的場景需要相應的基礎---而這些東西,學院里的卻未必夠用,多數情形下我們的程序員接觸的還是應用開發。
所以我明確的反對將這三樣東西提到過分的高度,生存逼迫你編程,興趣才能讓你成長。我們還在求生的過程中......

浙公網安備 33010602011771號