拍腦殼所想之
——戲言物件導向
說到protected這個詞,我不可避免的就會想到乙個概念——物件導向。那麼什麼是物件導向呢?其實我個人認為物件導向這個概念是一直在發展變化的,到了今天,物件導向這個詞也許讓它叫做面向抽象更加貼切。在剛剛建立物件導向這個概念的時候,大概連創造者對於到底什麼是物件導向都不是很清楚。要搞清楚物件導向(程式設計,或者設計)是什麼,也許得看看過去的軟體**都是什麼樣的。
i.西元前
軟體開發在最初的十幾二十年裡面,基本上就是面向過程的。面向過程的核心內容有兩項,乙個是控制流,另外乙個就是資料流。在這乙個時期裡面,軟體界最大的發展估計是資料結構與演算法這兩個「科目」了,這兩者分別對應著兩個「流」。在面向過程的軟體**裡面,執行主體是過程或者函式。乙個過程所代表的就是乙個動作,動作的物件(這裡還不是物件導向的物件)是一些資料,資料也許通過引數得到,也許通過全域性變數得到,還有一些常量或者預定義值。如果我們仔細想一下,就會發現這是乙個「動賓」結構的體系,比如說basic裡面比較著名的「line (x1, y1) -(x2, y2)」,翻譯成自然語言就是「畫一條(x1,y1)到(x2,y2)的直線」。類似的例子還有很多,比如c語言裡面的「printf("%srn", "hello world!");」。
可是主語在**?
ii.創世紀
面向過程的**裡面並沒有突出乙個主語,很多時候這個主語也並非不存在,就像上面的例子裡面,主語就是乙個螢幕。可是如果我們需要往印表機裡面畫一條直線呢?(或者列印乙個"hello world"。)在面向過程的**裡面,我們就不得不自己寫乙個printline的函式。(c語言往檔案裡面些東西就是fprintf。)如果我們要往遠端裝置上畫一條直線,那還要寫乙個remoteline,如果……不需要我多說,您也會覺得麻煩。圍繞著這樣乙個問題,人們就開始思考:是否能夠把主語明確的給寫出來?是否能夠讓我們少做一點重複性的工作?後來就有了物件導向這個東西,在物件導向是乙個「主謂賓」結構的世界,絕大多數東西都有乙個主語,比如我們所熟悉的「g.drawline(pen, pt1, pt2);」,由於我們有了「主語」,我們就可以讓不同的東西,用相似的方法做相似的事情。如果光是把g換成h,僅僅解決了「在這個視窗畫」與「在那個視窗畫」的問題,如果我們希望他能夠在其他型別的空間上畫,我們還需要容許主語的型別可以不完全相同。但我們要解決的更多問題還是概念相同之處,例如印表機的g和螢幕的g都能夠畫線,因此有了諸如繼承、封裝等概念。這就是物件導向的一切了嗎?
iii.改革開放
隨著物件導向概念的誕生,春風沐浴大地。正如上帝說要有光,於是有了光。上帝說要有毒蛇,於是有了毒蛇,上帝說要有蘋果,於是有了蘋果,結果亞當和夏娃吃了這個上帝創造出來的蘋果受到了上帝的「懲罰」。真不明白,既然上帝不希望亞當和夏娃吃這個蘋果,為什麼還要創造這麼乙個東西?其實上帝創造這個蘋果當然是不希望他們「吃」這個蘋果,創造這個蘋果實際上是為了產生浪漫的愛情以及其後千秋萬代的動人故事。如果你把這個蘋果僅僅看成是吃的,那麼接下來你看到的就是痛苦的懲罰。如果你看到的是背後動人的故事,那麼浪漫甜蜜等美好之辭就會充滿你的大腦。
物件導向也一樣,他的核心意義並不在於你把東西封裝成什麼樣了,不在於有什麼東西被繼承出來了,最重要的是他容許我們用抽象的方式來構建乙個軟體。比如當我們寫**寫到:
stream.write(buff, 4, buff.length - 4);
或者hashbuff = hasher.computehash(buff);
我們是否需要關心stream到底是什麼,hasher用的又是什麼演算法呢?如果我們由始至終,在做相應的東西的操作都用相同的stream物件和hasher物件,任務是否都應當能夠正確完成呢?應該是能夠正確完成的,因為這正是我們的期待。如果讓我們來設計某乙個stream,是否應該從這個角度去考慮如何設計這乙個類呢?如果我們定義這個stream變數,是否應該更抽象一點呢?考慮這麼乙個函式:
void dosomething(filestream stream, md5cryptoserviceprovider hasher, byte buff)
如果寫成如下形式將會更加靈活,也更加符合物件導向(面向抽象)的真實含義:
void dosomething(stream stream, hashalgorithm hasher, byte buff)
換句話說,所有的封裝、繼承、介面等等,實際上是為了提供抽象能力而存在的。如果我們把protected當作保護「某些方法的存在」這個秘密的話,那就大錯特錯了。保護這些秘密嚴格說來應該是密碼學的職責,而不是物件導向的職責。
iv.回顧歷史
物件導向的核心是面向抽象,但我們看到,實際發展的過程並非如此。我們在過去有著太多錯誤的概念了,比如說這個物件導向技術的物件導向,就太容易讓我們認為,這項技術的核心就是物件導向。於是很多時候我們寫乙個「物件導向」的程式充斥的過度的物件,氾濫的繼承,以及不知道為什麼的封裝。並且不少開發者,包括我在內,都曾經認為所謂的物件導向就是把一些要素抽象成物件,進行封裝,然後從某個基類派生出萬物。好比有乙個基類叫做物體,派生出活物與死物,活物派生出細菌病毒植物動物,動物裡面有猴雞狗豬和人,人裡面有張三李四王二麻子(還有個娃)。
沒錯,物件導向當然得包括這些,但是這不是全部,更不是根本。根本就是在於我們寫某些東西的時候,不需要關心具體的物件是什麼,只需要知道至少它應該是乙個什麼。比如上一節當中的例子,dosomething只需要知道stream是乙個流,而hasher是乙個雜湊演算法提供者就夠了。至於具體提供的是什麼樣的流和雜湊演算法,則不應當是我們關心的,而是使用我們這段**的使用者所關心的。如此一來,我們就可以在設計這一段我們所關心的功能的時候,不需要考慮過多的、過於具體的、不斷變化的問題。
仔細想想,我們是否真的已經明白了物件導向的核心所在呢?
v.封裝保護的是什麼
物件導向的封裝並非保護你的秘密,而是防止被錯誤使用,是為了明確劃分問題的界限。就「保護」這個詞而言,更進一步的講,它並非對使用該物件的使用者(下面稱為使用者)做出使用某個成員的授權,而是對延展該類的設計人員(下面稱為設計人員)做出延展問題領域的授權。現在讓我們回過頭來看一下wayfarer所寫的例子:
class base
}class derived:base
} class otherclass
**:一起**網
物件導向過程與物件導向
物件導向過程與物件導向 1 程式的發展經歷了兩個階段 面向過程 物件導向。2 對於物件導向與面向過程可以用乙個例子解釋,如乙個木匠要做乙個盒子,那麼這個盒子的出發點會有兩種方式 物件導向 先想好要做的盒子,之後在去找相應的工具去做。面向過程 不去想要做什麼樣的盒子,隨需取工具。物件導向三大特徵 封裝...
物件導向方法與物件導向測試
物件導向 object oriented,oo 方法認為,客觀世界是由各種物件組成的,任何事物都是物件,每乙個物件都有自己的運動規律和內部狀態,都屬於某個物件類,是該物件類的乙個元素。複雜的物件可由相對簡單的各種物件以某種方式而構成,不同物件的組合及相互作用就構成了系統。oo方法是當前的主流開發方法...
物件導向與基於物件 面向IO
物件導向和基於物件都有封裝 繼承。區別在於多型。基於物件是一種adt abstract data type 它封裝了一些複雜的操作,使之易於使用。繼承僅僅顯示了is a的關係,只是建立了乙個層次體系。物件導向的核心是多型。即通過一致的呼叫形式,根據物件的實際型別不同,可以自動完成不同的行為。舉個例子...