青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當(dāng)自強(qiáng)而不息

【ZT】敲響OO時(shí)代的喪鐘(1)


 值得懷念的世界,卻不值得回去!
——莊表偉

 面向過程的世界是完整的,統(tǒng)一的,也是容易理解的——對(duì)于程序員來說——或者說他只需要一種理解能力。這個(gè)世界雖然值得懷念,卻不值得再回去。因?yàn)椋覀儾辉傧癞?dāng)年的程序員那樣,只開發(fā)那些簡單的軟件了。很多人崇拜那些早起的“大牛”,其實(shí)平心而論,我們現(xiàn)在面對(duì)的問題的復(fù)雜程度,在他們當(dāng)年可以說幾乎無法解決。需求的復(fù)雜程度也不是他們當(dāng)年能夠設(shè)想到的。

 這是在秘魯發(fā)現(xiàn)的神秘的納斯卡巨畫,這樣巨大的地面藝術(shù),可以給我們對(duì)于面向過程的編程的結(jié)論一個(gè)可視化的比喻。面向過程的編程,只有一個(gè)統(tǒng)一的世界,他對(duì)于軟件的理解,始終不會(huì)離開計(jì)算機(jī)的操作與運(yùn)算本質(zhì),這就像在平地上作畫那樣,我們需要的一根長1米的直線,非常容易,兩點(diǎn)一線,一拉就出來了。但是當(dāng)我們需要在地面上畫一根5000米甚至更長的直線時(shí),如何保證畫出一條直線,就成為一個(gè)巨大的挑戰(zhàn)。當(dāng)視角無法升到足夠的高度時(shí),如此復(fù)雜的圖案幾乎是無法把握的。僅僅依靠結(jié)構(gòu)化的劃分,并不能完全的隔離復(fù)雜度的交互影響。單步跟蹤一個(gè)1000行代碼的程序并不困難,但是如果是100萬行代碼,甚至更多呢?

再看一張照片:

      

這是世界上最大的“埃及胡夫金字塔”。我們假設(shè),如果當(dāng)年法老在工程進(jìn)行到80%的時(shí)候,提出需求變更,希望金字塔尖能夠向右移動(dòng)10米。情況會(huì)如何?——會(huì)死好多勞動(dòng)人民的!如果希望向右移動(dòng)100米呢?如果希望有四個(gè)塔尖各在一個(gè)方向呢?如果。。。還好這一切都沒有發(fā)生,否則我們就不可能看到一個(gè)真正完工的金字塔。然而在軟件開發(fā)領(lǐng)域,當(dāng)“結(jié)構(gòu)化編程”面對(duì)“移動(dòng)金字塔”的需求變更時(shí),它只能破產(chǎn)!

可以得出一個(gè)比較關(guān)鍵性的結(jié)論是:

僅僅從計(jì)算機(jī)的角度出發(fā),對(duì)于更為復(fù)雜的需求,描述力不足。對(duì)于巨大的需求變更,應(yīng)變力不足。而這正是對(duì)于的軟件需求的必然發(fā)展趨勢。

所以,那個(gè)世界不值得回去,但是,OO真的幫到我們了嗎?

多年以后的今天,我們依然在思考這樣一個(gè)問題:“OO怎么就流行起來了呢?”學(xué)術(shù)一點(diǎn)分析,這個(gè)問題可以分為以下幾個(gè)部分:

1、OO之前的軟件開發(fā)困境何在?
2、當(dāng)時(shí)的開發(fā)人員如何解決那些困境?
3、那些解決困境的努力,為何會(huì)匯入OO的名下?
4、OO這個(gè)概念,從何而來?
5、OO的核心內(nèi)容是什么?
6、OO的實(shí)際目的是什么?
7、OO的理想目標(biāo)是什么?

困境

“需要一個(gè)超越于機(jī)器執(zhí)行層面的的認(rèn)識(shí)。”或者說,不能僅僅以“解空間”的語言描述解決方案,最好能夠以“問題空間”的語言描述解決方案。這是OO得以流行的真正動(dòng)力,因?yàn)镺O宣稱自己能夠更好的描述“真實(shí)世界”。

注意我要區(qū)分的幾個(gè)概念:“解決困境的努力”、“困境的根本原因”、“OO所宣稱的目標(biāo)”、“OO實(shí)際達(dá)到的效果”。因?yàn)樵谝酝腛O的宣傳中,這些概念是一個(gè)有機(jī)的整體,而卻認(rèn)為,其中有諸多“斷裂破碎”之處。

面向過程的編程,面對(duì)的困境其實(shí)相當(dāng)多,最根本的原因前面也已經(jīng)指出了。但是在當(dāng)時(shí),在具體的項(xiàng)目中,在特定的人看來,他們碰的,是各自不同的問題。在人工智能領(lǐng)域,在圖形化界面領(lǐng)域,面對(duì)的是模擬的問題。在企業(yè)應(yīng)用領(lǐng)域,面對(duì)的是數(shù)據(jù)訪問與保護(hù)的問題。從共同的困境來看,適應(yīng)變更,方便重用,系統(tǒng)健壯之類的要求,也是需要考慮的。

概念的發(fā)展歷程

首先聲明,這是一個(gè)假想的歷程,并非真實(shí)的歷史。真實(shí)的歷史,可以參考以下URL中的介紹:

      http://heim.ifi.uio.no/~kristen/FORSKNINGSDOK_MAPPE/F_OO_start.html

模擬:模擬的概念由來已久,但是如何模擬卻是一個(gè)大問題。
抽象數(shù)據(jù)類型(ADT):在對(duì)結(jié)構(gòu)(structure)進(jìn)行簡單的擴(kuò)展之后,ADT就順理成章的出現(xiàn)了。
封裝:對(duì)于ADT的理論總結(jié)可以表述為“封裝帶來了數(shù)據(jù)的安全性”。
繼承:一堆不能重用的代碼是“罪惡”的。繼承首先出來試圖解決這個(gè)問題。
多態(tài):是一個(gè)意外的收獲,如果各個(gè)對(duì)象都提供同一個(gè)名字的方法,似乎就可以不去管他們的區(qū)別。

在這些努力與嘗試之后,面向?qū)ο髾M空出世,從哲學(xué)的高度總結(jié)了這些努力:“你們都是正確努力的一部分,你們都在試圖更好的描述真實(shí)世界,真實(shí)的世界里一切都是對(duì)象,所有的對(duì)象在一個(gè)分類系統(tǒng)里各安其位,對(duì)象之間通過消息相互‘招呼’。應(yīng)用OO思想,描述真實(shí)世界的運(yùn)行,就是編程的主要工作。”

但是事實(shí)上呢?編程并不是描述真實(shí)世界!而是描述需求世界。不同的需求世界,需要不同的“世界觀”。這一點(diǎn),面向?qū)ο蟛]有考慮到。當(dāng)時(shí)流行的思想是通用編程語言,使用一種語言解決世界上所有的開發(fā)難題。而要整體解決各不相同的開發(fā)難題,只能將目光投向“真實(shí)世界”,那是各個(gè)差異巨大的“問題空間”的唯一一致的背景。

面向?qū)ο蟮恼軐W(xué)破綻

在此特別感謝徐昊,這一部分該如何寫,我始終沒有想好,在與他討論之后,我基本理出了一個(gè)思路。

面向?qū)ο笥袃蓚€(gè)哲學(xué)基礎(chǔ),原子論與形而上學(xué)。這兩大基礎(chǔ),在哲學(xué)的發(fā)展歷程中,曾經(jīng)如日中天,無可置疑(在古希臘那時(shí)候),如果說這樣的哲學(xué)不偉大,那就是我太狂妄了,但是如果有人說:“西方哲學(xué)在之后的幾千年里沒有進(jìn)步,古希臘哲學(xué)就是西方哲學(xué)的頂點(diǎn),因此面向?qū)ο罄硭?dāng)然的應(yīng)該建立于這兩大哲學(xué)之上!”你會(huì)相信嗎?

1、原子論

西方哲學(xué)的發(fā)展,經(jīng)歷了兩次變革,一次是認(rèn)識(shí)論轉(zhuǎn)向;一次是語言轉(zhuǎn)向;第一次轉(zhuǎn)向使哲學(xué)的基礎(chǔ)從本體論和形而上學(xué)變?yōu)檎J(rèn)識(shí)論,從研究超驗(yàn)的存在物轉(zhuǎn)到研究認(rèn)識(shí)的主體和主客體關(guān)系;第二次轉(zhuǎn)向把對(duì)主客體的關(guān)系的研究變成了對(duì)主體間的交流和傳達(dá)問題的研究。把對(duì)主體的研究從觀念和思想的領(lǐng)域轉(zhuǎn)到了語言的領(lǐng)域(語句及其意義);這兩次轉(zhuǎn)向的代表人物分別是笛卡爾和維特跟斯坦。

————《OO, OO以后, 及其極限》waterbird

看來我可能是比較淺陋了,在我看了waterbird的《OO, OO以后, 及其極限》之后,曾經(jīng)深深的自責(zé)過。看來OO沒有我想的那么土,不是直接來自古希臘哲學(xué),而是從維特根斯坦繼承而來的。waterbird的引用而后總結(jié)的一段維特根斯坦的話,使我對(duì)維特根斯坦大為佩服。

小結(jié)2: 2 主要說明 --- 事實(shí)(facts)由原子事實(shí)(atomic facts)所組成;原子事實(shí)(atomic facts)由更基本的對(duì)象(objects)所組成;我們的關(guān)于外部世界的主觀描述圖畫,與它所描述的外部世界具有相同的邏輯結(jié)構(gòu);注: (這即是相當(dāng)于軟件開發(fā)中的"建模")

還好,在我昨天列出了閱讀書目之后,gigix提醒我看了另外一篇文章:《維特根斯坦早期思想及其轉(zhuǎn)變》,這是一個(gè)正兒八經(jīng)的哲學(xué)家的文章,總算讓我見識(shí)到了軟件開發(fā)這個(gè)行當(dāng)里,頗有些不懂哲學(xué)的家伙,拿著哲學(xué)來唬人的。

原子事實(shí)是最簡單的事實(shí),無法再從中分析出其他事實(shí),分析的結(jié)果只能是對(duì)象。因此,原子事實(shí)是對(duì)象的結(jié)合或配置。“對(duì)象是簡單的”〔2.02〕,不可再加以分析,所以,對(duì)象就是簡單對(duì)象,不過,為清楚起見,維特根斯坦還是經(jīng)常采用“簡單對(duì)象”這個(gè)說法。簡單對(duì)象這個(gè)概念引起很多困惑和爭論,其實(shí)維特根斯坦自己也很猶豫,他在筆記中寫道:“我們的困難是,我們總說到簡單對(duì)象,卻舉不出一個(gè)實(shí)例來。” 他曾考慮過關(guān)系、性質(zhì)、視域上的小片、物理學(xué)里的物質(zhì)點(diǎn)。他還說個(gè)體如蘇格拉底、這本書等,“恰恰起著簡單對(duì)象的作用”。一條可能的思路是把簡單對(duì)象理解為一種邏輯要求,一個(gè)邏輯終點(diǎn):“簡單對(duì)象的存在是一種先天的邏輯的必然性。” 在《邏輯哲學(xué)論》中,維特根斯坦大致采用了這條路線,這本書里從未舉例說明什么是簡單對(duì)象。

維特根斯坦說的對(duì)象,是OO中的對(duì)象嗎?一個(gè)正兒八經(jīng)的現(xiàn)代哲學(xué)家的困惑,OO大師們考慮到了嗎?只有樸素、甚至可以說是幼稚的原子論觀點(diǎn),才會(huì)輕松的混淆:事實(shí)、原子事實(shí)、對(duì)象和具體的物質(zhì),物體。對(duì)于OO來說,對(duì)象非常容易被發(fā)現(xiàn),幾乎隨手一指,都能點(diǎn)到一個(gè)對(duì)象。

從語言哲學(xué)來說,最為困難的是:“有沒有一種語言,可以清晰地、完整地描述這個(gè)世界?”邏輯原子論原本認(rèn)為有可能。但是,維特根斯坦的后期哲學(xué)轉(zhuǎn)向,恰恰指出了一個(gè)困境,而這個(gè)困境即時(shí)是人類歷史上最為天才的頭腦,也無法“走出”的。德國人最具有理性的思維能力,而其中最為天才的頭腦卻碰上了理性思維的天花板。維特根斯坦很難理解,越是德國天才,他的語言越是晦澀。倒是從中國哲學(xué)的角度,往往能夠看透其中的掙扎。老子在幾千年前就說:“道可道,非常道,名可名,非常名”。因?yàn)樵噲D準(zhǔn)確、無誤、無失漏的命名、描述世界的努力,是不可能成功的。

因此,我現(xiàn)在可以斷言,面向?qū)ο蟊澈蟮脑诱摚贿^是直接師承古希臘哲學(xué)的簡單、樸素、幼稚的原子論,這樣的原子論哲學(xué),早已破產(chǎn)。作為哲學(xué)史的研究對(duì)象,自有其價(jià)值,而作為指導(dǎo)軟件開發(fā)那么現(xiàn)代活動(dòng)的哲學(xué)理論,實(shí)在是太不適用了。

2、形而上學(xué)

當(dāng)我寫下這個(gè)標(biāo)題的時(shí)候,內(nèi)心無比惶恐。這么大個(gè)題目,是我這個(gè)半路出家,Google成才的家伙能夠談?wù)摰膯幔慷嗌僬軐W(xué)家一輩子“皓首窮經(jīng)”,也不過就是研究個(gè)形而上學(xué)啊。

當(dāng)初,維特根斯坦去找羅素,問到:“你看我是不是一個(gè)十足的白癡?”羅素不知他為什么這樣問,維特根斯坦說:“如果我是,我就去當(dāng)一個(gè)飛艇駕駛員,但如果我不是,我將成為一個(gè)哲學(xué)家”。可見哲學(xué)這東西,只有真正的天才才有能力去研究它。

還好,我并不是要研究形而上學(xué),我只是要研究面向?qū)ο蟊澈蟮男味蠈W(xué)哲學(xué)基礎(chǔ)。
我也不是要證實(shí)這個(gè)哲學(xué)基礎(chǔ)的正確性與適用性。我只需要證明“面向?qū)ο蟊澈蟮哪莻€(gè)形而上學(xué)基礎(chǔ)是不正確的、是不適用于軟件開發(fā)的。”

面向?qū)ο蟮膬纱蠛诵母拍钍牵?#8220;對(duì)象”與“類”。“一切皆是對(duì)象”是由樸素原子論而來的。“萬物皆有類屬”就是由亞里斯多德的形而上學(xué)來的。

對(duì)于亞里斯多德的形而上學(xué)理論不熟悉的朋友,可以即時(shí)補(bǔ)課,中國人民大學(xué)哲學(xué)系的《西方哲學(xué)史》有好幾節(jié)專門講這個(gè)方面:《亞里斯多德的實(shí)體論I》、《亞里斯多德的實(shí)體論III》。還有就是到Google上去專門搜一下亞里斯多德的邏輯學(xué)說,看完以后,咱們回來接著說。

咱們用自己的話說一下:“種”、“屬”、“屬差”以及“定義”這幾個(gè)概念。

種:是一個(gè)大的概念,假設(shè)已經(jīng)預(yù)先定義好了的。
屬:所有屬于某一種的概念,都是那一種下面的屬。
屬差:同屬一種的、同一級(jí)別的屬之間的差別,或者說個(gè)性。
定義:通過種加屬差,可以定義一個(gè)屬的概念。

舉例說明:人是二足直立動(dòng)物。人是一個(gè)需要被定義的屬,動(dòng)物是人之所屬的種,二足直立是人作為動(dòng)物的共性之外,擁有的個(gè)性,也就是屬差。

懂得初步的面向?qū)ο缶幊痰耐緜儯銈兌伎闯鰜砹税桑蠖鄶?shù)OO語言也是這么定義類的。你定義一個(gè)Animal,再用Person去繼承Animal。在Animal里有一些屬性與方法,在Person里再加一些人所特有的。很多很多的面向?qū)ο蟮慕炭茣铮踔辆褪侵苯佑眠@個(gè)定義來舉的例子。

問題出在哪里?或者有人會(huì)問:“這樣有什么不對(duì)嗎?”

我們可以通過“種+屬差”來定義一個(gè)新的屬嗎?定義成立的前提是什么?先要有種的定義。然后才可能有屬的定義。種的定義又是哪里來的呢?在一個(gè)種的概念之上,必然存在一個(gè)更普遍的種,一個(gè)更大的范疇。在亞里斯多德來說,在所有的種之上的種是“存在”,而存在是無法被定義的。而在面向?qū)ο蟮恼軐W(xué)里,即使是這一個(gè)最基本的哲學(xué)困境也被忽略了,無法被定義的概念,被代換為無需由程序員定義的概念(Object)。屬差的區(qū)別在哲學(xué)家看來,是本質(zhì)的,是基于深刻認(rèn)識(shí)才能提出的。而在面向?qū)ο蟮恼軐W(xué)里,種的共性就是基類所定義的“屬性與方法”,而屬的個(gè)性,就是對(duì)于基類的擴(kuò)展。“種+屬差”變成了“公用代碼+擴(kuò)展代碼”。

當(dāng)概念定義這樣一個(gè)“問題域的描述手段”,演變成“減少重復(fù)代碼原則”之后。Class繼承的概念就越發(fā)的模糊不清了。我們來總結(jié)一下:

1、面向?qū)ο笤韭暦Q的描述真實(shí)世界的目標(biāo),采用的工具卻是樸素的“種加屬差”的方式。
2、面向?qū)ο蠓治鲋校l(fā)現(xiàn)具體的對(duì)象還算是容易的,發(fā)現(xiàn)“種”的概念卻是困難的。
3、在實(shí)際應(yīng)用中,種概念的發(fā)現(xiàn)與定義,被偷換為公共代碼的抽取。
4、由于基類的定義的隨意性,導(dǎo)致子類不但可以擴(kuò)展基類的行為與特性,還可以覆蓋(改變)基類的行為與特性。
5、由于哲學(xué)概念的與開發(fā)概念的混淆,使得在OO領(lǐng)域IS-A、Has-A、Like-A成為最為繞人的概念。

在寫完了哲學(xué)分析部分之后,我總算是喘了一口氣,仿佛穿越了最幽暗的深谷,終于走出了自己最不擅長的領(lǐng)域了。

后來在MSN上和曹曉鋼聊了挺長時(shí)間,對(duì)于OO的批判,他認(rèn)為有點(diǎn)過頭了。經(jīng)過我的解釋,他提出了一個(gè)更好的建議,清楚的說明自己批判的OO,究竟是哪一個(gè)階段的OO,然后才不至于誤傷到已經(jīng)改善過后的OO。所以我打算整理一下對(duì)于OO發(fā)展階段的看法,寫在下面:

1、面向?qū)ο蟮恼Z言:先有語言
2、面向?qū)ο蟮姆治雠c設(shè)計(jì)理論:再有理論
3、面向?qū)ο蟮脑O(shè)計(jì)原則的全面總結(jié):再有原則
4、設(shè)計(jì)模式的初步提出:然后才有了真實(shí)的經(jīng)驗(yàn)總結(jié)
5、重構(gòu)方法的提出:然后才考慮到代碼設(shè)計(jì)的細(xì)節(jié)上的改善
6、AOP概念的提出:打破OO封裝的“封印”
7、新語言的出現(xiàn):Python、Ruby之類面向?qū)ο蟮膭?dòng)態(tài)語言:更加方便的語言?
8、ASM、CGLIB、Mixin之類技術(shù)的出現(xiàn):OO喪鐘的先聲

具體的對(duì)于各個(gè)階段的分析,將在隨后展開,目前對(duì)于OO的哲學(xué)分析,基本上是針對(duì)原始的OO概念的。隨后的OO技術(shù)的發(fā)展,也在試圖解決由于OO的哲學(xué)基礎(chǔ)假設(shè)帶來的問題,當(dāng)然,越是解決問題,也就離OO的本意越遠(yuǎn),現(xiàn)在有人還以為OO在不斷發(fā)展,而事實(shí)上,OO早就盛極而衰,目前已經(jīng)處在破產(chǎn)的前夜了,我的這篇文章,就是打算使這一天,早日到來!
 

類型系統(tǒng)

“事實(shí)上,我們猜想是,如果沒有知識(shí)表示和自動(dòng)推力工作的幫助,這些問題(指類,繼承)是無法僅僅通過計(jì)算機(jī)語言設(shè)計(jì)的方式來處理的。”——SICP 2.5,中文版136頁,角注118。

Elminster那篇論述,正好和我的文章形成一個(gè)互補(bǔ)關(guān)系,他以極為清晰的表達(dá)語言,說明了OO打算以類型化方式描述真實(shí)世界,所面臨的難題。這也使我不必再次動(dòng)腦子思考如何回答JavaCup的哲學(xué)方面的疑問了。而下面這一段話我想特別再次引用一下:

就我個(gè)人來說,比較傾向于認(rèn)為這條最終是走不通的死路,人是從事物的特征與屬性歸納出它的“類型”,而不是相反。某種意義上說,“類型”是為了節(jié)省描述時(shí)間而產(chǎn)生的 …… 唔,這個(gè)太遠(yuǎn)了,所以就此打住。

大家記住這段話中的,特征、屬性、類型這幾個(gè)關(guān)鍵字。我先繞個(gè)小彎再回到這個(gè)話題上來。

我之前分析的面向?qū)ο蟮恼軐W(xué)漏洞時(shí),也有不少朋友認(rèn)為,說:“面向?qū)ο蟛荒芎芎玫拿枋稣鎸?shí)世界,并非一個(gè)有意義的指控。OOA、OOD本來就是用來對(duì)需求建模的。也就是打算描述需求世界。”

其實(shí)我的指控分為兩個(gè)階段,一方面,OO所依據(jù)的哲學(xué)導(dǎo)致了軟件開發(fā)的苦難,而且至今余毒未清。另一方面,即使是指打算對(duì)需求建模,OO的技術(shù)手段也是有缺陷的。

就這么說吧:OO的類型系統(tǒng),原本是從ADT來的。一個(gè)抽象數(shù)據(jù)類型,將數(shù)據(jù)與操作封裝在一起,是出于對(duì)于數(shù)據(jù)被“莫名其妙的修改”的擔(dān)心。但是,結(jié)果呢,一個(gè)ADT如果不支持繼承,那么它的代碼就無法被重用。所以O(shè)O就在ADT的基礎(chǔ)上增加的一個(gè)繼承,通過繼承的方式來復(fù)用以有的代碼。這樣的思路原本沒有太大的問題,如果它僅僅只想表達(dá)各種自定義數(shù)據(jù)類型的話。

但是在OO的哲學(xué)提出之后,一切皆是對(duì)象,所以一切出于類型體系之內(nèi),對(duì)于數(shù)據(jù)類型的定義,擴(kuò)展到了對(duì)于現(xiàn)實(shí)世界中各種實(shí)體的類型定義,整個(gè)一個(gè)類型系統(tǒng),其內(nèi)在的語義大大擴(kuò)展復(fù)雜化了。更糟糕的是——引用Elminster的話是從事物的特征與屬性歸納出它的“類型”——而因?yàn)镺O封裝也就是隱藏了內(nèi)部數(shù)據(jù),事物的特征與屬性,從其本質(zhì)屬性,被轉(zhuǎn)義為對(duì)外的提供的操作接口。但是,要分析一個(gè)實(shí)體的本質(zhì),而不是實(shí)體的外部表現(xiàn),更不僅僅是“我能對(duì)他做什么”。這才是實(shí)體分析有可能成功的關(guān)鍵,而在OO的語言設(shè)定中,這卻是難以做到的。

我們來看兩張圖片:

      

這是在SICP里討論類型系統(tǒng)的第一張圖片,我稱之為“OO成功案例”。

     

這是在SICP里討論類型系統(tǒng)的第二張圖片,我稱之為“OO失敗案例”。

為什么一個(gè)能夠成功,而另一個(gè)卻會(huì)失敗?以往的解釋其實(shí)比較“直覺”。看著這個(gè)圖,就想當(dāng)然的以為:“這是因?yàn)槎嘀乩^承導(dǎo)致的!”事實(shí)上呢?

第一張圖中所顯示的成功,很多人會(huì)認(rèn)為這是由于這一個(gè)對(duì)象塔中的每一個(gè)對(duì)象都能夠支持加減乘除運(yùn)算。而在幾何圖形中,這樣一致的操作接口不存在了。而事實(shí)上,正是因?yàn)閺?fù)數(shù)、實(shí)數(shù)、有理數(shù)、整數(shù),在本質(zhì)屬性上有一致之處,他們才能表現(xiàn)出一致的“可加減乘除性”。而不是相反。當(dāng)我們畫出第二張對(duì)象關(guān)系圖的時(shí)候,也不是根據(jù)幾何圖形可以接受的操作類型來進(jìn)行分類與顯示繼承關(guān)系的,而是根據(jù)不同的幾何圖形的本質(zhì)屬性的相近程度來劃分類型體系的。多邊形的本質(zhì)是: “多條有限長直線組成了一個(gè)封閉圖形”,而三角形與四邊形的本質(zhì)則是,邊的數(shù)量分別為三和四。等腰三角形的本質(zhì)是,不但邊的數(shù)量為三,而且其中有兩條邊的長度相等,直角三角形的本質(zhì)是不但邊的數(shù)量為三,而且其中有一個(gè)直角。如此等等......

各位,請(qǐng)?jiān)俅嗡伎歼@樣的分類體系的內(nèi)涵。

      我的結(jié)論是:“一個(gè)類型,是由其本質(zhì)決定了所能表現(xiàn)出的可操作性,而不是有其所能接受的操作決定了其本質(zhì)。然而,OO正好把這個(gè)問題搞反了!”

繼承、重用、多態(tài)

OO的核心思想就是繼承,那么,OO為什么要繼承呢?對(duì)于這個(gè)問題,OO的理論大師們有好多個(gè)版本的解釋:

1、“這是OO的類型系統(tǒng)自然的要求。設(shè)想一下生物學(xué)的分類系統(tǒng):動(dòng)物——>哺乳動(dòng)物——>靈長類動(dòng)物——>人類。或者設(shè)想一下我們的概念系統(tǒng):機(jī)器—— >交通工具——>汽車——>小轎車。這樣的現(xiàn)象在你的生活中難道不是隨處可見嗎?”

2、“如果你有一個(gè)類,叫做車輛,這個(gè)車輛類能夠移動(dòng),現(xiàn)在你要建立一個(gè)子類,叫做家庭型轎車,你就可以直接繼承車輛這個(gè)類,而不需從頭再寫移動(dòng)部分的代碼了呀!”

3、“如果你有三個(gè)類,三角形、四邊形、正方形,他們都需要顯示在屏幕上,那么你就可以建立一個(gè)基類叫多邊形,提供一個(gè)draw()方法,然后讓那個(gè)三個(gè)類都繼承這個(gè)多邊形類并且覆蓋那個(gè)draw()方法,這樣,你就可以在繪圖的時(shí)候,統(tǒng)一對(duì)一種多邊形類進(jìn)行操作,不用去管那個(gè)對(duì)象究竟是哪一種多邊形。”

這三種解釋,是最為典型的OO繼承的好處的解釋了。但是你如果仔細(xì)的看,就能發(fā)現(xiàn)這三種好處,分別描述的是:“概念的特化”、“代碼的重用”以及“接口的重用”。或者可以分別命名為:“繼承”、“重用”、“多態(tài)”。

“這樣有什么問題嗎?”,也許有人會(huì)問。問題就出在這三個(gè)好處是用一種方法提供,而這三個(gè)好處相互之間有時(shí)是相通的,有時(shí)又是矛盾的!當(dāng)我們運(yùn)用OO語言,來寫這樣的繼承的語句時(shí),一切都是“攪和在一起的”!

假設(shè)Class A有兩個(gè)屬性和兩個(gè)方法:String a1;int i;void f1();void f2();當(dāng)我們另外寫一個(gè)Class B去繼承Class A的時(shí)候,我們可以繼續(xù)使用某些屬性,而覆蓋另一些屬性,還可以繼續(xù)使用某些方法,而重寫另一些方法。還可以添加一些新的屬性,還可以添加一些新的方法。如果在加上各種訪問控制符的限定與修正。誰能夠告訴我:“這個(gè)Class B究竟想干什么?!”

也許有人會(huì)繼續(xù)為這樣的現(xiàn)象辯解:“這是對(duì)于繼承的誤用,正確的OO程序不會(huì)這樣的!”
但是,這個(gè)辯解并不成立,幾乎所有的OO的編程語言,都沒有在繼承問題上做出太多“非此即彼”的限制,原因只有一個(gè),那就是,在某些特定的場合,這樣的“拼盤”是相對(duì)最合理的編碼方式。

我們前面還沒有提到多重繼承,一個(gè)允許多重繼承的語言,會(huì)讓這個(gè)問題更為復(fù)雜,也可以說會(huì)使得場面越發(fā)的混亂。讓我們舉一個(gè)例子,這是Eiffel語言的繼承語法,讓我們看一看面對(duì)繼承這樣一件事情,一個(gè)程序員,究竟需要考慮多少問題。來源是《對(duì)象揭密》,我就一邊抄,一邊直接翻成中文了。

繼承    :inherit 父類列表
父類列表  :{父類 ";" ... }
父類    :類名[特性適配說明]
特性適配說明:[Rename]    :重命名以消除名字沖突
[New_exports] :重新設(shè)定特性導(dǎo)出的分組
[Undefine]   :撤銷定義
[Redefine]   :重定義以取代虛函數(shù)
[Select]    :更加高級(jí)的功能
end

最值得看的就是這個(gè)特性適配說明,更加深入的說明還是各位自己去找書看吧。這就是號(hào)稱優(yōu)雅的解決了OO繼承問題的Eiffel語言。他所謂的優(yōu)雅,可以不客氣的說,就是把所有的麻煩都明確的告訴你,而不是像C++和Java那樣,假裝什么事情都沒有發(fā)生過。但是,麻煩依然在那里,并沒有減少,根本的解決方法,是應(yīng)該不讓這樣的麻煩出現(xiàn)呀!可是OO確實(shí)無法做到這一點(diǎn)。

因?yàn)樗褦?shù)據(jù)和操作封裝在了一起,然后又偷換了實(shí)體本質(zhì)的概念,在這樣的情況下的OO,他的繼承是肯定搞不好的!

接口、泛型與重用

 先說點(diǎn)提外話,我從小學(xué)開始學(xué)習(xí)BASIC和LOGO,到后來學(xué)習(xí)了FoxBase、FoxPro、C/C++、Visual Basic、VBScript、JavaScript、PHP,之后才開Java編程,之后也沒有再換過語言。誠實(shí)的說,只有Java語言,是我認(rèn)認(rèn)真真的學(xué)習(xí)和研究的。對(duì)于面向?qū)ο蟮睦斫猓彩窃趯W(xué)習(xí)和使用Java之后,才真的開始深入思考這方面的問題,在此之前,我甚至認(rèn)為所有的語言都沒有什么本質(zhì)的差別,面向某某和面向某某之間也沒有什么大不了的差別。

所以當(dāng)我想要寫這篇文章的時(shí)候,其實(shí)內(nèi)心是相當(dāng)惶恐的,我對(duì)于面向?qū)ο蟮牧私猓鋵?shí)只來自于一種語言,那就是Java,而Java是不是就等于是面向?qū)ο竽兀慌率遣荒苓@么說的吧。

JavaEye有人留言:“不要到時(shí)候說不圓影響了一世英名。”;“討論這個(gè)問題,我還是建議去看 SICP,你會(huì)發(fā)現(xiàn)所有OO具有的思想SICP都講到了”;“實(shí)際上我很懷疑莊某最后還是跑不出SICP的框架,如果是這樣,那么其理論的價(jià)值就要打折扣了。”我那個(gè)慌啊,趕緊到書店去買了SICP回來仔仔細(xì)細(xì)的啃,然后再在MSN上向T1好好的請(qǐng)教過幾次,最后總算放心了,我的思路,不在SICP的框架內(nèi),或者說,不在SICP作者的思考局限之內(nèi)。

還有人留言,提到了C++:“OO門檻較高是不爭的事實(shí)。的確很多人并沒有進(jìn)入。有句話可以套
用,沒有三年的功底,最好不要說懂C++。幸運(yùn)的是這門東西的回報(bào),會(huì)告訴你所付出的是完全值得的。”我又慌了,C++背后的面向?qū)ο螅蔚雀呱睿覅s從來沒有用C++做過哪怕1000行以上的程序,這等門檻都沒有入的人,有資格評(píng)價(jià)面向?qū)ο竽敲创蟮氖虑椋s緊的,我又到書店去買了一本《對(duì)象揭秘》,我對(duì)于當(dāng)年gigix的一篇介紹《編程語言的宗教狂熱和十字軍東征》始終記憶猶新,里面提到了面向?qū)ο螅岬搅薈++的無數(shù)缺點(diǎn),還提到了Eiffel,一個(gè)據(jù)說是比C++要好無數(shù)倍的面向?qū)ο蟮恼Z言。如果我要想加快速度,又想保證質(zhì)量的話,從《對(duì)象揭秘》里面應(yīng)該可以找出很多現(xiàn)成的彈藥吧。

抱著急于求成的功利主義目的,我開始仔細(xì)看這本《對(duì)象揭秘》,一看之下,真是大有收獲:

*C++果然毛病多多,而且作為第一個(gè)大面積流行的OO語言,OO的實(shí)際含義更多的來自于C++。
*Java的毛病少了很多,因?yàn)樗氲囊恍└拍睿辉偈褂玫囊恍└拍睿蟠蟮臏p少了C++式OO編程的陷阱,只是這樣一來,在復(fù)雜問題上使用Java語言,往往會(huì)寫出很丑陋的程序。
*Eiffel同樣也是反思C++缺點(diǎn)的語言,但是它的改進(jìn)基本上是表面的,Java是使問題簡化,哪怕犧牲語言的表達(dá)能力,而Eiffel是使問題表面化、集中化,陷阱雖然沒有了,但是問題一個(gè)都沒有減少,反而因?yàn)?#8220;讓人眼花繚亂的復(fù)雜語法”,讓人望而卻步。
*《對(duì)象揭秘》是一本很一般的書,作者花了十多年的時(shí)間攢出一本書來,實(shí)質(zhì)上還是BBS里一段一段討論的水平。

————————————————————————————————————————

好了,題外話結(jié)束,接下來討論正題,今天主要研究OO的概念中兩個(gè)較為邊緣的概念“接口”與“泛型”,以及探討一個(gè)實(shí)際上最為重要的誤用——“重用”。

1、關(guān)于“接口”

接口是什么東西?接口是一個(gè)很奇怪的東西!接口之所以奇怪,因?yàn)樗膩睚埲ッ}實(shí)在是讓人看不懂。基礎(chǔ)的OO概念中,并沒有接口的位置,因?yàn)榘凑?#8220;經(jīng)典的”面向?qū)ο笏季S,一個(gè)沒有代碼、沒有內(nèi)部數(shù)據(jù),只有方法說明的東西,是無法理解的。

追根溯源的說,首先是在C++的面向?qū)ο髮?shí)踐中,發(fā)現(xiàn)了對(duì)于“抽象類”的需要,為什么需要抽象類呢?因?yàn)榇a重用的需要,比如一個(gè)基類,其實(shí)就是一堆公用代碼,有一個(gè)名字把它框起來叫一個(gè)類,但是完全沒有道理把它實(shí)例化。像這種“發(fā)育不完全的類”,該拿它怎么辦呢?OK,就讓它不能“出生到這人世間來”。抽象類的本質(zhì)就是這個(gè)樣子的。

到了Java,因?yàn)閷?duì)于多繼承的恐懼,Java完全擯棄了多重繼承,這是Java被攻擊得最多的地方,因?yàn)檫@樣的單根繼承,實(shí)在是因噎廢食——因“怕被繼承體系搞亂”廢“更加方便道代碼重用”。于是Java就說了:我們有一個(gè)“安全的”多重繼承,叫做“接口”,這個(gè)接口,完全沒有代碼,只有說明,所以絕對(duì)安全,但是由能夠?qū)崿F(xiàn)多重繼承的好處云云。

而事實(shí)上呢?多重繼承的根本目的,并不是像Java所宣稱的那樣為了“同時(shí)繼承多種類型”,而是為了“同時(shí)重用多組代碼”。接口這一發(fā)明,完全不能達(dá)到多重繼承的代碼重用效果,卻被宣稱為多重繼承的替代品。其實(shí)質(zhì)是:“從一個(gè)發(fā)育不完全的實(shí)體,變成了一張徹底沒有發(fā)育的皮”。

最為令人感到奇怪的,還不是“接口的出現(xiàn)”,而是“面向接口編程”的出現(xiàn),Java被冠以“面向接口的語言”的美名,“面向接口設(shè)計(jì)”成了OO的設(shè)計(jì)原則之一,“針對(duì)抽象,不要針對(duì)具體”,成了OO名言之一。實(shí)在是......


關(guān)于OO的設(shè)計(jì)原則,我下面還會(huì)專門討論,這里先指出一個(gè)大漏洞:“抽象類的那個(gè)抽象,和與具體相對(duì)的那個(gè)抽象,根本就不是一回事!”

 

繼承、多態(tài)與泛型沖突的一個(gè)例子

寫技術(shù)文章,例子其實(shí)很難舉,特別是找到有殺傷力的,決定性的例子,相當(dāng)困難。昨天我接著看《對(duì)象揭密》,總算被我找到一個(gè),當(dāng)然,它那上面的解說,實(shí)在是比較模糊,因此我決定用自己的話重新敘述一遍,代碼示例用Java的泛型語法,但是要表達(dá)的意思,確實(shí)所有的具有泛型的OO語言都需要面對(duì)的。

java代碼:

public class X {
protected int i;
public void add(int a){
i=i+a;
}
}

public class Y1 extends X {
public void add(int a){
i=i+a*2;
}
}


public class Y2 extends X {
public void add(int a){
i=i+a*3;
}
}

這是三個(gè)最簡單的類,Y1和Y2都繼承了X,并且重寫了add函數(shù)。當(dāng)然,這只是舉例,實(shí)際上這三個(gè)add中,有兩個(gè)是不合理的。

java代碼:

ArrayList listx=new ArrayList();
ArrayList listy1=new ArrayList();
ArrayList listy2=new ArrayList();

listx.add(new X());
listx.add(new Y1());
listx.add(new Y2());

listy1.add(new Y1());
listy2.add(new Y2());

這幾行代碼都非常簡單,只是為了說明一個(gè)道理,在ArrayList和ArrayList中,能夠放的就只有Y1和Y2了,而在以X為泛型的ArrayList中,就可以放X、Y1、Y2了。而當(dāng)然了,這樣的用法,只怕是不合泛型的目標(biāo)的,本來就是希望能有一個(gè)類型的自動(dòng)檢查與轉(zhuǎn)換,都放在ArrayList中,幾乎就等于都放在ArrayList中了。

現(xiàn)在我們有這樣一個(gè)需求,對(duì)于得到的ArryaList,能夠一一調(diào)用里面的對(duì)象的add(int a)方法,當(dāng)然了,只要這個(gè)ArrayList里的對(duì)象都是X或者X的子類就行了。我們可以寫出這樣的代碼:

java代碼:

public void addListX(ArrayList listx){
for(int i=0;isize();i++){
X x=listx.get(i);
x.add(1);
}
}

是不是很簡單?且慢,這個(gè)addListX函數(shù),我們能夠把listx傳遞給它,但是能不能把listy1和listy2

也傳遞給它呢?如果我們能夠把listy1和listy2傳遞給它,就相當(dāng)于執(zhí)行了如下的類型轉(zhuǎn)換代碼:

java代碼:

ArrayList listy1=new ArrayList();
ArrayList listx=listy1;

這樣做行不行呢?在Java和C++中,是不行的。也就是說,如果我們要想只寫一遍addListX這樣的函數(shù),而不用再多寫兩遍addListY1();addListY2();這樣的函數(shù),就需要把所有的X,Y1,Y2這樣的類型都放到ArrayList這樣的容器里,否則,addListX函數(shù),是不接受ArrayList和ArrayList類型的。即使Y1和Y2是X的子類型,ArrayList與ArrayList也毫不相干。不能相互轉(zhuǎn)換。

有人也許會(huì)說,為什么這么限制嚴(yán)格呢?Eiffel就沒有這么這么嚴(yán)格的限制,他允許ArrayList自動(dòng)轉(zhuǎn)型為ArrayList,這樣是好事情嗎?如果listy能夠被轉(zhuǎn)型為ArrayList,那么就可以往里面添加Y2類型的對(duì)象了,這又是原來的泛型ArrayList不允許的。也就是說:除非addListX能夠保證只對(duì)listy1做只讀操作,否則,類型安全性這個(gè)泛型原本要追求的目標(biāo)就不能實(shí)現(xiàn)了。而如果要追求絕對(duì)的類型安全性,像C++和Java那樣,那么代碼要么就得寫三遍,要么X、Y1、Y2類型的對(duì)象就得都放到ArrayList這樣的泛型容器里去。

注意看這其中的左右為難的狀況,繼承、多態(tài)、泛型,并不是真正正交的、互不干擾的,而是在一個(gè)相當(dāng)普通的目標(biāo)面前,他們就起了沖突了。


posted on 2007-10-01 02:46 lovedday 閱讀(1352) 評(píng)論(1)  編輯 收藏 引用 所屬分類: ▲ Software Program

評(píng)論

# re: 【ZT】敲響OO時(shí)代的喪鐘(1) 2013-09-25 10:47 blackTangle

博大精深啊  回復(fù)  更多評(píng)論   

公告

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

隨筆分類(178)

3D游戲編程相關(guān)鏈接

搜索

最新評(píng)論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国内综合精品午夜久久资源| 欧美成人午夜激情视频| 欧美在线视频免费| 亚洲一区视频在线| 午夜一区在线| 久久精品综合| 欧美激情第8页| 99国产精品国产精品久久| 亚洲剧情一区二区| 亚洲一区二区三区乱码aⅴ| 午夜亚洲性色视频| 亚洲一区一卡| 国产日产亚洲精品| 韩国一区二区三区美女美女秀| 好吊日精品视频| 亚洲蜜桃精久久久久久久| 亚洲欧美国产精品va在线观看 | 亚洲三级影院| 亚洲精品在线一区二区| 亚洲免费在线视频| 欧美激情导航| 国产综合婷婷| 亚洲午夜精品久久久久久浪潮| 久久爱另类一区二区小说| 亚洲电影av| 欧美亚洲在线观看| 欧美日韩mp4| 在线国产精品播放| 亚洲免费在线观看视频| 亚洲高清自拍| 久久激情一区| 国产精品久久久久高潮| 91久久久国产精品| 久久香蕉精品| 亚洲欧美日韩在线| 欧美日韩小视频| 1024亚洲| 久久久五月婷婷| 在线视频一区观看| 欧美激情一区二区久久久| 国产一区二区三区免费在线观看 | 亚洲欧洲日韩综合二区| 久久精品理论片| 亚洲作爱视频| 欧美国产91| 亚洲福利国产| 久久夜精品va视频免费观看| 亚洲图片在区色| 欧美日韩一本到| 中文久久乱码一区二区| 亚洲电影免费观看高清完整版| 欧美一区午夜视频在线观看| 国产精品久久影院| 亚洲男人第一网站| 99热在线精品观看| 欧美日韩成人一区二区| 亚洲精选大片| 亚洲日本激情| 欧美日韩精品福利| 一区二区三区日韩在线观看| 亚洲国内精品| 欧美激情欧美激情在线五月| 亚洲国产小视频在线观看| 欧美freesex8一10精品| 麻豆乱码国产一区二区三区| 亚洲第一精品影视| 欧美在线精品一区| 亚洲一二三四区| 国产精品高潮呻吟久久av无限 | 激情文学一区| 久久夜色精品亚洲噜噜国产mv| 久久福利毛片| 亚洲国产经典视频| 亚洲国产婷婷香蕉久久久久久| 欧美成人精品三级在线观看| 亚洲人成小说网站色在线| 亚洲欧洲精品成人久久奇米网| 欧美精品18+| 亚洲欧美一区二区精品久久久| 亚洲欧美综合一区| 亚洲激情专区| 一本综合精品| 国内久久精品| 亚洲欧洲日韩在线| 国产伦精品一区二区三区免费| 久久久久久久精| 欧美激情一区二区三区成人| 亚洲欧美国产视频| 久久久精品国产免大香伊| 亚洲欧洲一区| 午夜在线不卡| 日韩亚洲一区在线播放| 亚洲网站视频| 亚洲精品久久久久久下一站| 亚洲桃花岛网站| 亚洲国产精品成人| 亚洲综合视频在线| 99国产一区二区三精品乱码| 亚洲欧美日韩精品久久久| 在线观看一区二区精品视频| 中国亚洲黄色| 亚洲毛片视频| 欧美专区第一页| 亚洲欧美成人精品| 免费成人毛片| 久久蜜桃精品| 国产精品视频一| 亚洲日本成人女熟在线观看| 国产一区高清视频| 在线视频欧美日韩精品| 91久久午夜| 久久视频国产精品免费视频在线| 亚洲欧美在线另类| 欧美日韩精品在线| 亚洲三级影院| 日韩视频一区| 欧美精品三级| 亚洲国内在线| 亚洲国产日韩欧美| 久久久人成影片一区二区三区| 欧美亚洲视频在线观看| 欧美肉体xxxx裸体137大胆| 91久久久一线二线三线品牌| 亚洲福利专区| 久热精品视频在线| 嫩草成人www欧美| 影音先锋日韩资源| 久久精品男女| 久久一区二区三区四区| 国产亚洲综合性久久久影院| 亚洲欧美日韩在线综合| 一区二区亚洲精品| 宅男精品视频| 亚洲制服av| 国产精品久久久久久久第一福利 | 欧美制服丝袜| 久久久高清一区二区三区| 国产日韩综合| 久久久噜噜噜久久中文字幕色伊伊| 久久精品视频免费| 国产一区二区精品久久| 久久久国产成人精品| 久久伊人一区二区| 亚洲成人资源| 欧美久久久久久| 日韩亚洲欧美中文三级| 亚洲一区二区黄| 国产欧美一区二区三区久久人妖 | 快播亚洲色图| 亚洲国产一区二区三区a毛片| 亚洲黑丝在线| 欧美精品一区二区三区一线天视频| 亚洲精品国产精品国自产在线| 99国产精品久久久久久久| 欧美亚州一区二区三区| 欧美亚洲系列| 亚洲国产成人av| 亚洲婷婷免费| 国产亚洲激情| 免费看精品久久片| 亚洲视频在线观看| 美国十次成人| 一区二区电影免费在线观看| 国产精品你懂的在线| 久久av一区二区三区漫画| 欧美大香线蕉线伊人久久国产精品| 亚洲精品一区二区三区蜜桃久| 国产精品高潮在线| 久久这里只有| 99精品国产热久久91蜜凸| 久久国产精品99精品国产| 亚洲国产精品电影在线观看| 欧美日韩精品综合| 久久久久久久一区二区| av成人动漫| 欧美福利小视频| 久久精品国产久精国产爱| 99精品国产在热久久婷婷| 国产手机视频精品| 欧美日韩国产色视频| 久久久999精品视频| 一本色道久久综合一区| 毛片av中文字幕一区二区| 亚洲一区二区在线免费观看视频| 一区二区三区在线观看视频| 国产精品国产三级欧美二区| 欧美成人免费网| 久久久精品国产一区二区三区| 一区二区三区欧美激情| 欧美成人综合一区| 久久九九久精品国产免费直播| 一区二区免费在线观看| 亚洲高清精品中出| 国产一区免费视频| 国产精品久久久爽爽爽麻豆色哟哟| 免费在线亚洲| 久久亚洲一区| 久久精品人人做人人爽电影蜜月| 午夜精品久久久99热福利| 亚洲另类视频|