|
目錄 Catelog
目錄 Catelog
序言 Perface
真經第一章:世界 Waltanschauung
真經第二章:抽象 Abstraction
真經第三章:層次 Arrangement
真經第四章:繼承 Inheritance
真經第五章:耦合 Couple
真經第六章:運作 Moving
真經第七章:建造 Build
真經第八章:刻畫 Delineate
真經第九章:模式 Pattern
真經第十章:悟道 Doctrine
后記 Afterword
參考文獻 Reference
序言 Perface
“佛曰:苦海無涯,回頭是岸。——佛教用語”
面向對象(Object-Oriented),這是一條令無數開發人員魂牽夢繞的短語。幾乎每個軟件分析師、設計師和程序員都時刻將它銘記于心,對它頂禮膜拜。然而,對大多數人來說,它又像是天邊的霞光,可望而不可及,無數次伸出雙手,總是抓不住這虛無縹緲的圣物。于是,我們依然每天將面向對象高高供其,卻始終無法悟得其道,更不要談嫻熟運用其道法了。
面向對象像一灘苦海,無數人游弋其中,卻久久不得其要領;類、對象、繼承、多態、接口、UML、設計模式……無數概念看得我們眼花繚亂,卻也悟不透其真諦。佛教有云:苦海無涯,回頭是岸。如果置身苦海中無法脫離,那么,我們是否應該提高一個層面去看這片苦海:從哲學及科學的角度,去審視面向對象。
曾有人說:藝術的極致是科學,科學的極致是哲學。此話不無道理,牛頓、愛因斯坦等科學界泰斗,在其后期都不約而同地轉向哲學研究。當然,這里本人無意更不敢將自己與上面兩位大師相提并論,而且本人也不奢求此文能成為一篇頗有思想的佳作。只不過,本人在平時的實踐和思考中,略有小得,于是,在這里拿出,和大家一起分享討論。雖然膚淺,但希望本文能成為一絲波紋,為各位脫離苦海提供一點點的推動作用。
真經第一章——世界 Weltanschauung
“世界觀(德文:Weltanschauung)意為‘著眼世界之上’,是人們對世界的總的根本的看法。任何哲學問題的探討,歸其出發點和本源,都是世界觀的問題。什么樣的世界觀決定了什么樣的哲學觀點。——馬克思”
我們知道,哲學領域中,最根本的對立是唯物主義和唯心主義的對立,而附屬其下,又有許多對立,如形而上學和辯證法的對立、可知論和不可知論的對立等等。這些對立形成了哲學的基本體系、派別和出發點。實際上,這些對立,都是世界觀的對立。世界觀,簡而言之即如何看待這個世界。世界觀是一切哲學問題的本源和出發點。
同樣,在程序世界里,也有著不同的世界觀。而這其中最根本的對立便是過程論和對象論的對立,這個對立,衍生出了面向過程和面向對象兩種方法論。于是,要真正理解面向過程和面相對象,我們就不得不先深究一下程序世界中這兩種世界觀。
首先要提到的是,不論是過程論還是對象論,都承認一點,那就是程序世界本質上只有兩種東西——數據和邏輯。數據天性喜靜,構成了程序世界的本體和狀態;邏輯天性好動,作用于數據,推動程序世界的演進和發展。盡管上述觀點是統一的,但是在數據和邏輯的存在形式和演進形式上,過程論和對象論的觀點截然不同。
過程論認為:數據和邏輯是分離的、獨立的,各自形成程序世界的一個方面(ASPect)。所謂世界的演變,是在邏輯作用下,數據做改變的一個過程。這種過程有明確的開始、結束、輸入、輸出,每個步驟有著嚴格的因果關系。過程是相對穩定的、明確的和預定義的,小過程組合成大過程,大過程還可以組合成更大的過程。所以,程序世界本質是過程,數據作為過程處理對象,邏輯作為過程的形式定義,世界就是各個過程不斷進行的總體。
對象論認為:數據和邏輯不是分離的,而是相互依存的。相關的數據和邏輯形成個體,這些個體叫做對象(Object),世界就是由一個個對象組成的。對象具有相對獨立性,對外提供一定的服務。所謂世界的演進,是在某個“初始作用力”作用下,對象間通過相互調用而完成的交互;在沒有初始作用力下,對象保持靜止。這些交互并不是完全預定義的,不一定有嚴格的因果關系,對象間交互是“偶然的”,對象間聯系是“暫時的”。世界就是由各色對象組成,然后在初始作用力下,對象間的交互完成了世界的演進。
上面的描述也許有些不夠直觀,那么,下面我們通過一個實際的例子,直觀感受一下在兩種世界觀下,對同一件事物是怎么看的。
大家都聽過這么個智力題吧:
說有甲、乙、丙三人住店,一間房30。于是每人10元,共計給店老板30元住進一間房。后來店老板發現弄錯了,房價應該是25元,于是給小二5元讓小二退給房客。小二黑心,貪污了2元,退給甲乙丙每人1元。這樣房客每人付了10-1=9元,三九27,加上小二貪污的2元,共29元,問那1元哪里去了?
不知各位聰明的看官是否已經參透其中玄機。不過參不透也沒有關系,這不是重點,重點是,我們現在來分別用過程論和對象論分析一下這件事。
首先,我們來看看過程論是怎么看這件事情的。
圖1.1、過程論看世界
如圖1.1所示,這就是過程論下看這件事的樣子。左邊是過程的各個步驟,而右邊紅字表示在每個過程步驟的數據情況,這種數據情況反映了世界當前的狀態。為簡單起見,我們只考慮在這個過程中參與分配的數據。
初始時甲乙丙各10元,老板和小二沒有錢,這可以認為是這個過程的初始狀態,這些數據是輸入。隨著各個步驟的進行,數據不斷更新,而在每個步驟,數據如何更新、更新多少,都是由步驟嚴格確定的。經歷五個步驟后,數據變為甲乙丙各1元,老板25元,小二2元,這就是終止狀態,也是這個過程的輸出。
下面,再來看看對象論下如何看這件事。
圖1.2、對象論看世界
對象論眼中,世界是由各種對象組成的,每個對象有自己的數據和邏輯,如圖1.2所示。在這件事里,有五個基本對象:甲、乙、丙、小二和老板(注意,這里我們還沒有提到類和抽象等概念,所以不要讓固有思維跳出來,在這里要只認識對象,不認識類等概念。現在我們只討論世界觀的基本問題:程序世界的本質,至于更具體的問題,留待后面討論)。每個對象有自己的一系列數據和邏輯,這里只列出了我們關心的部分。
然后呢?沒有然后了。沒錯,在對象論眼里,這就是這件事的本質模樣,這件事所涉及的東西就是這么幾個對象,本來它們各自獨立,老死不相往來。只不過在“住店”這個外部驅動力下,幾個對象“偶然”、“暫時”互相聯系,利用其他對象提供的公開服務,完成了一些交互。在交互中,各自的數據可能會發生一些變化,但對象的本質沒有變。這里也要注意,這種交互雖然在一定程度上由既定邏輯預定義,但不像過程論認為“萬事萬物都已注定”,在對象論下,對象間的交互是“偶然的”、“暫時的”,這次五個人因為住店這個外部驅動力交互了一次。但下次如果魏國和蜀國交戰變為驅動力,他們間的交互就不是拿錢給錢了,而是刀兵相見。所以,對象論不認為“一切都已注定”。
通過上面一個例子,不知各位是否已經明白程序世界中兩種世界觀看事物的不同。下面,有一些問題還要明確一下。
I. 過程論和對象論是兩種看世界的觀點,沒有孰對孰錯、孰好孰壞之分。
II. 過程論和對象論不是一種你死我活的絕對對立,而是一種辯證統一的對立,兩者相互滲透、在一定情況下可以相互轉化,是一種“你中有我、我中有你”的對立。如果將對象論中的所有交互提取出來而撇開對象,就變成了過程論,而如果對過程論中的數據和邏輯分類封裝并建立交互關系,就變成了對象論。
III. 過程論相對確定,有利于明晰演進的方向,但當事物過于龐大繁雜,將很難理清思路。因為過程繁多、過程中又有子過程,容易將整個世界看成一個紛繁交錯的過程網,讓人無法看清。
IV. 對象論相對不確定,但是因為以對象為基本元素,即使很龐大的事物,也可以很好地分離關注,在研究一個對象的交互時,只需要關系與其相關的少數幾個對象,不用總是關注整個流程和世界。但是,對象論也有困難。例如,如何劃分對象才合理?對于同一個驅動力,為什么不同情況下參與對象和交互流程不一樣?如何確定?其實,這些困難也正是面向對象技術中的困難。
綜上,我們知道在程序世界中,存在著過程論和對象論兩種對立的世界觀,并且其各有千秋,無法定奪孰好孰壞。但是,對象論似乎更有助于分析規模較大的事物。本文是探討面向對象的,所以,在下文中,都會選擇對象論作為世界觀。這種以對象為本的世界觀,也是本文后續一切的基礎和出發點。
真經第二章——抽象 Abstraction
“金、木、水、火、土元素,構成宇宙萬物,并作為各種自然現象變化之基礎——五行說”
上文探討了世界觀問題。我們知道,要想真正理解面向對象,首先要用對象論去審視世界。而在對象論中,萬事萬物的本源是對象,對象是組成世界的基本元素。但是,要真正看透一個世界,只有基本元素是不行的。
中國古代的樸素唯物主義哲學中,比較有代表性的是五行說。五行說認為,世界的基本元素是“金、木、水、火、土”,但若說世界只有“金、木、水、火、土”,也是不成的,所以后續有云:五行相生相克,相互交織結合,組成了大千世界。雖然從現代科學角度看,五行說并不完全準確,但其有一點事非常正確的,那就是世界首先有基本元素,然后基本元素還要衍生出各種其它東西。
在第一章中,我們說了在對象論中,對象是組成世界的基本元素,但這還不能構成真正的世界。下面,我們來看看對象是如何構成和衍生出其它事物的。
和真實世界中構成和衍生方式不同,程序世界中,最重要的衍生方式是抽象。例如,眾所周知的類(Class),就是從對象上首先抽象出來的概念。下面我們看一看類是怎么來的。
從哲學角度說,先有對象,然后才有類,類和對象是“一般和特殊”這一哲學原理在程序世界中的具體體現。這可能和很多人的直覺不同,因為在具體寫程序時,是先定義類,然后才能實例化對象。在這里,我們是從哲學層面進行探討,所以,對象是本源,類的概念是衍生。為什么?因為從認識論來說,首先有具體認知能力,才能有抽象認知能力,抽象認知能力是一種高層的,人類特有的認知能力,它使我們可以從大量具體認知中,舍棄個別的、非本質的屬性,提取出共同的、本質的屬性,是形成概念的必要手段。
還是以住店的故事為例吧。在我們的世界觀中,那個故事涉及了五個對象,剛開始我們沒有抽象的概念,而只是從具體認知角度對這五個對象進行認知:首先是甲,他有頭、有身子、有胳膊有腿,頭上有眼睛鼻子耳朵,他還有個名字叫劉備,有個身份是顧客……除了這些數據,這個對象還可以做一些事情,可以吃飯、呼吸、喝水,還能給錢和拿錢……好的,一通認知后,我們對甲這個對象有具體認知了;然后,我們對乙進行認知:他有頭、有身子、有胳膊有腿,頭上有眼睛鼻子耳朵,他還有個名字叫關羽,有個身份是顧客……除了這些數據,這個對象還可以做一些事情,可以吃飯、呼吸、喝水,還能給錢和拿錢……認知完了,接著是丙、小二和老板……當具體認知足夠多后,我們發現一件事情:這幾個對象很相似啊,有相似的數據(但具體值可能不同),有相同的邏輯,于是,我們的抽象認知能力告訴我們,這五個對象很相似,可以看做一類東西,于是,我們給出一個類,叫“人”,并且認為這五個對象都是“人”這個類的具體例子,我們叫其為實例。以后遇到類似的對象,我們都可以知道,這個對象屬于“人”類。
圖2.1、“人”類的由來
所以,類其實是抽象認知能力作用于程序世界的基本元素——對象后所衍生出來的抽象概念,是抽象思維在程序世界中物化后的產物。當然,現實世界中每個對象都有無數的數據和邏輯,但在具體到程序世界時,我們往往只關心具體場景中相關的數據和邏輯。例如,在住店場景中我們關心現金這則數據,至于這個人力氣大不大無所謂;而如果上戰場打仗,我們就關心攻擊力和力量,現金就不重要了。
知道了類是怎么來的,那么類的作用是什么,我們為什么需要類呢?
類可以幫助我們方便地認識和定義世界中的對象。這個作用是顯而易見的。例如當今世界有60幾億人,如果不會抽象思維,我們每遇到一個人,都要認知一遍:啊!這個對象有眼睛,有耳朵,有鼻子有嘴,有胳膊有腿……要是真這樣,世界也太瘋狂了。有了類的概念,我們就可以只記類的數據和邏輯,而對于具體對象,只要知道它屬于什么“類”,一切就都知道了,所需要區分的只是不同對象的數據具有不同值而已。
其實,這不僅僅是類的作用,我們進行抽象思維,就是為了這個目的。
這一章敘述了類的哲學本質、衍生過程和作用。要記住,抽象是形成和衍生概念的基本方法,不只是類,后面的很多概念,都是通過抽象形成的。所以,我們可以說:上天只給了這個世界各種對象,但我們用抽象去更好地認識世界。
真經第三章——層次 Arrangement
“道生一,一生二,二生三,三生萬物——老子”
上文提到,在對象論中,抽象是衍生概念的基本方法。但是你有沒有一個疑問?所謂抽象,是對許多對象撇開個性,抽出共性,這樣,抽象過程就不是確定的、唯一的。例如,我們在看過很多對象后,發現有一類對象有四個輪子、有發動機、可以駕駛、是可以被意識反映的客觀實在。我們抽象出一個叫“汽車”的類。這次抽象中,我們將有四個輪子看做了共性,但是,如果撇開這條性質,僅看后三條,摩托車、輪船、飛機都符合,于是,我們又可以抽象出“機動交通工具”類。再把有發動機撇掉,自行車、腳踏三輪車,甚至馬都符合,所以,又得出個“代步工具”類,最后,把可以駕駛也撇掉,只剩下“是可以被意識反映的客觀實在”,如果這樣,所有物質都符合,這樣,就得出一個“物質”類。
這下子困難就來了,你說我家的奔馳應該歸到哪一類呢?我家的奔馳和一只是不是一類東西呢?如果從前三類看,當然不是,但是從最后一個“物質”類看,又確實是一類東西。那到底哪一個對?事情究竟是怎樣的?其實答案很簡單:歸到哪一類都正確。至于后一個問題,無法回答,因為這個問題單獨問根本沒有意義。為什么?
關鍵在于:抽象是有層次的。
上文說到,對象是基本,我們從對象上抽象出類。但是,世界可并不是一層對象一層類那么簡單,對象抽象出類,在類的基礎上可以再進行抽象,抽象出更高層次的類。所以經過抽象的對象論世界,形成了一個樹狀結構。
圖3.1、抽象層次樹示例
圖3.1展示了一棵抽象層次樹的示例。不要懷疑,在對象論中,經過初步抽象思維加工后的世界就是這樣樣子。本來,世界只有各個具體對象(最底下紫色文字表示的層次),這是第0層,是一切抽象的本源和起始,然后,抽象思維作用其上,抽象出初步的類,然后在既有類和對象的基礎上可以再進行抽象……如此歸納下去,最終整個世界歸結于樹的根節點:本體。所謂本體,即萬物之源、萬物之本,是哲學層面上最高層次的抽象。在這里,我們將其看成是一個特殊的類,作為抽象層次樹的根。
千萬不要小看了這棵抽象層次樹,如果能參透其中的奧秘,就能明白很多面向對象中的玄機,而且很多問題就都迎刃而解了。這種抽象層次樹理論也是后續諸多內容的理論基礎。例如,OO中重要的概念——繼承(Inheritance)和多態(Polymiorphism),如若探究其哲學本源,就是從這里來的。
下面,對這棵樹做一些必要的說明。
I. 這是一棵單根樹,最頂層“本體”為唯一的根,最下層葉子節點為基本對象。一切中間節點都為類。
II. 越往上的類抽象層次越高,具體度越低,其內涵越小,外延越大;越往下的類抽象層次越低,具體度越高,其內涵越大,外延越小。說明一下,所謂類的內涵,是指類對屬于自己的對象的說明力度,而外延是指類能包含的具體對象的總和。例如,家用電器這個類,其內涵是使用電作為能源并完成特定功能的家用器具,各個電冰箱、洗衣機、電磁爐、游戲機、DVD機等都在其外延之內;而娛樂家用電器這個類,作為比家用電器更低層次的類,其內涵除了“使用電作為能源并完成特定功能的家用器具”外,還要是具有娛樂功能,其內涵明顯大了,但外延卻縮小了,只包括了各個游戲機、DVD機等對象。
III. 抽象層次樹不是從根部向下長的,而是從葉子節點向上歸納生成的。
IV. 某一個葉子節點所代表的對象可以歸入所有其祖先結點所代表的類
V. 直接問兩個葉子節點屬不屬于一個類沒有意義,而要指定抽象層次才有意義。例如在較低層,一輛寶馬屬于汽車,而一只蒼蠅屬于昆蟲,不是一類。但如果指定在較高層比較,兩個都屬于具體物質,屬于一個類。
VI. 我們定義,如果一個節點CNode非葉子節點也非根節點,那么在哲學意義上,這個節點繼承于其父節點PNode,并且說PNode是CNode的泛化。
VII. 我們定義,如果一個節點CNode非葉子節點也非根節點,如果強行將它看成其任何一個祖先節點ANode,并當做ANode使用,那么在哲學意義上,叫做多態性。
先說明這么多了,隨著后續內容的深入,還會有更多豐富的內容進來。例如,后面會看到,所謂的“里氏代換原則(LSP)”,在哲學本質上不過是在這棵樹上所加的一條限制規則,而“面向接口編程”、“低耦合、高內聚”、“依賴倒置”等一系列耳熟能詳的短語,歸結到哲學上也只是這棵樹的一些精化。
另外,看了上面的理論,我想本章開頭留下的疑問也已經煙消云散了吧。
再提示一遍,這棵樹非常重要,得其精髓,就能理解諸多OO中概念、原則和方法的本質。后續討論中,抽象層次樹理論將作為重要的理論基礎。
真經第四章——繼承 Inheritance
“子類型必須能夠替代掉其父類型——Barbara Liskov”
這一章我們討論繼承(Inheritance)。
我們先看一看繼承在哲學意義上時怎么來的。對象論的世界觀認為,世界的基本元素是對象,我們將抽象思維作用于對象,形成了類的概念,而抽象的層次性形成了抽象層次樹的概念。接著,我們就可以定義:在抽象層次樹上,除根節點和葉子節點外,任一節點CNode非嚴格繼承其所有祖先節點所組成的集合中的任一元素,而CNode嚴格繼承其父節點PNode。
繼承概念,看似簡單,若深入思考,卻隱藏眾多玄機。首先,繼承描述的實際是抽象層次樹上祖先節點與子孫節點的關系,但我個人一直不贊成使用繼承(Inheritance)一詞來描述這種關系,而推薦使用泛化(Generalization)一詞。為什么呢?因為我們已經知道,從哲學和認識論角度來說,是先有對象,然后有類;先有子類,然后有父類,是一種自底向上形成的體系。而繼承一詞,明顯帶有自頂向下的暗示,因為往往是先有爺爺、有父親繼承爺爺、然后才能有兒子繼承父親。這樣,就容易讓人誤解成是先有父類才有子類。所以,為了更好的體現繼承的哲學本質,我更傾向于使用“泛化”代替“繼承”。當然,由于繼承一詞已經被普遍使用和接受,接下來我還是會沿用繼承一詞,只不過希望各位時刻牢記,其實是先有了子類,才從子類泛化出父類。
當然,當父類被抽象出來后,可能還會有新的子類加進來。但是,當初父類一定是從某些子類中泛化出來的,而不會是憑空突然出現的。
探討了繼承的本質,然后我們來探討繼承存在的意義。一切存在的東西都是有意義的,否則就不可能存在。注意,這里的“意義”是中性詞,指事物存在的原由,不要理解成褒義。
我們需要繼承這個概念,本質上是因為對象論中世界的運作往往是在某一抽象層次上進行的,而不是在最低的基本對象層次上。舉個例子,某人發燒了,對其他人說:我生病了,要去醫院看醫生。這句簡短的話中有一個代詞“我”和三個名詞“病”、“醫院”、“醫生”。這四個具有名詞性的詞語中,除了“我”是運作在世界的最底層——基本對象層外,其他三個都運作在抽象層次,在這個語境中,“病”、“醫院”、“醫生”都是抽象的,他并沒有在醫院里拉著某個醫生對別人說:我生了這個,需要去這里看這個。但是,本質上他確實是生了一個具體的病,要去一個具體的醫院看一個具體的醫生,那么在哲學上要如何映射這種抽象和具體呢?就是靠繼承, 拿醫生來說吧,所有繼承自“醫生”類的類所指的所有具體對象都可以替換掉這里具體的醫生,這都不影響這句話語義的正確性。
所以,繼承的哲學作用就是:規定了抽象與具體之間的可映射性。形式化一點說:設G(c1,c2)意為c1非嚴格泛化自c2,I(c,o)意為對象o屬于c的外延,其中c1,c2,c均為類,o為對象。那么,c可在哲學語義上映射成o,當且僅當o∈{o|I(c,o)}∪{o|I(c’,o) 且 G(c,c’)}
如果你討厭看形式化的東西,那么上面藍色文字不看也罷,但是,有一條原則你一定很感興趣,那就是著名的開放-關閉原則(OCP)。
開放-關閉原則(OCP):軟件實體應該可以擴展,但不可以修改。
為什么忽然扯到OCP呢?因為,OCP正是上文討論的哲學原理在程序世界的具體表述。我們來對比看一下,到底OCP是個什么意思。
還是上面看病那個例子,什么叫可以擴展?就是說,因為在某個抽象層次是進行表述,就不能把話說死了,不能全是這個、那個的把每個對象都指派明白。如,那句話改成“我的右腳扭到了,要去北京航空航天大學醫院去看胡青牛醫生”,這句話就沒有擴展性可言了,所有話都說死了,你如果去的是北醫三院或臨沂市人民醫院,那么語義就不對了,而如果找的不是胡青牛而是華佗或扁鵲,語義也不對了。為什么無法擴展?因為所有點都指定了具體的對象。
而原話“我生病了,要去醫院看醫生”則擴展性很大,因為只要不違反可映射性定義,映射到任何符合條件的對象都正確。擴展性和靈活性大大提高了。所以,“可以擴展”四字從哲學上其實是要我們在設計和開發軟件時提高抽象層次,不要總在具體對象層面上進行處理。這下,你明白為什么說OCP可以提高軟件的可擴展性和靈活性了吧。
再來說說“不可以修改”,因為如果隨便亂改,那就天下大亂了。還是醫院那個例子,“醫院”這個類所映射到的對象,一定是治病的地方。如果這東西隨便改,例如明天“醫院”和“食堂”的概念對換了,那麻煩了,我們所有人都要改,要把兩個概念從腦子中對換過來,全世界的書、報紙、InterNET……凡是依賴這兩者進行表述的地方都要改,那不是天下大亂么?軟件世界中也會發生這種牽一發而動全身的問題。所以我們提倡設計好的類一定要“對修改關閉”。
以上,就是OCP的哲學意義。
不過,要想世界正常運作,只有OCP似乎還有點問題。到目前為止,我們都是在抽象層次樹已經存在,并且假定它完全正確的前提下討論的,可是,我們并沒有任何規則限制抽象層次樹的正確性,例如,如果我把食堂掛到醫院下,讓食堂成為醫院的子類,在理論上時沒有錯的,但如果這樣隨便亂規定繼承關系,那么一切依賴繼承正確性的原則、概念都沒有意義了。所以,只有OCP是不夠的,需要對繼承進行一個限制。
Barbara Liskov在1987年的OOPSLA大會上發表了一篇文章——《Data Abstraction and Hierarchy》,其中提出了一個非常重要的原則,叫里氏代換原則(LSP)。
里氏代換原則(LSP):子類型應該能代替掉其父類型,且代替后程序運行情況不會錯亂。
我們還是用例子去理解LSP。
現代辦公幾乎都要用到個人計算機,個人計算機本身是一個抽象概念,臺式PC是其中一個子類。后來,發明了筆記本電腦,我們想把筆記本電腦歸為個人計算機的子類,是否合理呢?根據LSP,我們將臺式PC都替換成筆記本電腦,世界應該是照常運行的(當然,實際情況可能復雜些,有些地方不能用筆記本電腦替換,但這里我們忽略這種差別)。我們辦公時依賴的類是“個人計算機”,而筆記本電腦完全可以替代這個類型而使得世界運行正常,所以,我們說將筆記本電腦歸于個人計算機的子類是符合LSP的。
后來,又發明了轉基因黃瓜,我們也想將它歸到個人計算機的子類中去,行不行呢?好的,現在我們再運用LSP,將世界上每個依賴個人計算機的地方都替換成一根轉基因黃瓜。好的,世界人民都瘋了!明顯這種替換會令世界運行錯亂。所以,我們不能讓轉基因黃瓜繼承個人計算機。
上面的例子是顯而易見的,但有些卻不那么明顯。例如,現在問,獸醫是醫生的子類嗎?這個問題,一下子還真不是很好回答,但我們可以LSP一下,現在,我們把醫院里的醫生都替換為獸醫,你還敢去醫院看病嗎?嗯,這下子不用我多說了吧。
最后一定要說明的是,LSP應用于程序世界和現實世界時有很大差別的,現實世界繁雜、不確定性因素多,而程序世界簡單、確定。總之,LSP就是讓你記住一條,凡是系統中有繼承關系的地方,子類型一定能代替父類型,而且替換后程序運行要正常。換言之,繼承是一種嚴格的“IS-A”關系,也是“一般和特殊”的哲學原理在程序世界中的體現。
繼承的話題就討論到這里了。很多朋友在運用繼承時有疑惑,或不能很好的確定繼承關系,歸其根本是沒有真正理解繼承的意義。只要能理解繼承的本質意義,加上OCP和LSP的運用,是可以寫出正確的繼承體系。
真經第五章——耦合 Couple
“一只蝴蝶在巴西輕拍翅膀,可以導致一個月后德克薩斯州的一場龍卷風——蝴蝶效應”
做程序的人,往往感覺“耦合(Couple)”不是什么好東西。經常有人、有書、有文章對我們諄諄教導:要降低耦合,要降低耦合……久而久之,好像耦合在程序界成了貶義詞,弄得我們恨不得把耦合從程序里全部拿掉。
這誤解可委屈耦合了。要是哪天沒了耦合,這世界還真玩不轉。其實耦合還有另一個名字,叫“聯系”,試問要是世界上所有對象間的聯系都沒了,世界還能運作么?耦合的存在是世界演進的途徑,如果沒有耦合,世界就變成了“死世界”,無法演進和發展。所以,耦合可是好東西,我們要感謝它!但是任何東西都有兩面性,過度的耦合確實會令世界的運作產生困難,所以我們提倡降低耦合,這些是后話。
下面,我們探討各種耦合式怎么出現的。
上一章講述了繼承,其實,繼承的概念出現后,有父子、祖孫關系的類就有了一種聯系,這種聯系叫做“泛化耦合”。這就是我們認識的第一種耦合。
泛化耦合(Generalization Couple):由于泛化(繼承)關系的存在,在兩個有祖孫、父子關系的類間形成的一種邏輯關聯。
然后,我們討論另一種耦合。
在文章開始,我們說對象論將對象看做基本元素,而對象中有數據和方法。在現實世界中,數據并不總是簡單數據。客觀存在一些對象,它們的數據是另一個或另一些對象。例如,一個具體的羊群,有一項數據是很多具體的羊。其中羊也是對象。當抽象成抽象的“羊群”和“羊”類的時候,這種包含關系也隨之被抽象到了類中,由此在兩個類之間就形成了耦合。
這種耦合出現的哲學基礎是,對象本身固有的包含關系,在進行事物抽象時被同時抽象到了類中。所以,我個人將其稱為包含耦合。
包含耦合又分為兩種情況,一種是被包含對象單純聚合在包含對象中,但沒有形成哲學意義上“整體與部分”的關系,這是一種相對較弱的聯系,叫做聚合。例如,上例中羊群和羊就是聚合關系,如果拿掉一兩只羊,羊群還是羊群。
聚合(Aggregation):一種弱的擁有關系,體現A對象可以包含B對象,但B對象不是A對象的一部分。
另一種情況是,被包含對象和包含對象形成了哲學意義上“整體與部分”的關系,如汽車和輪子,把輪子拿掉,汽車就不再是完整意義上的汽車了。這種關系叫做組合。
組合(Composition):一種強的擁有關系,體現了嚴格的部分和整體的關系,部分和整體具有一樣的生命周期。
通過上面的探討,我們認識了泛化耦合、聚合和組合三種耦合形式,最后,還有一種耦合叫依賴。什么是依賴呢?我們知道,在對象論中,將世界的演進看成是在初始作用力下,對象之間相互調用、相互協作完成的。如果兩個類在需求范圍內,既定邏輯上存在協作的可能,那么這兩個類就存在依賴關系(或叫關聯關系)。其實,我們常說的“低耦合,高內聚”、“降低耦合”等建議,主要是針對依賴說的。
依賴(Dependency):由于邏輯上相互協作可能,而形成的一種關系。
好的,到目前為止,我們已經認識了四種基本耦合。下面用一副圖,直觀感受一下世界的各種耦合。
圖5.1、耦合示例
圖5.1展示了幾種耦合的示例。其中汽車和交通工具屬于泛化耦合,輪子和方向盤組合于汽車,汽車聚合成車隊,而汽車和司機具有依賴關系。這幅圖只是耦合的一個小片段,實際上,世界上各種對象形成了一張復雜的耦合網,正因為有耦合的存在,世界才能演進。正如馬克思主義哲學所說:聯系是普遍的、客觀的。所以,耦合的存在,有其深刻的哲學意義。
不知你是否會有這樣的疑問:文章開始,不是說對象論將對象看做相互獨立的嗎?怎么又耦合起來了。這是矛盾的嗎?實則不矛盾。因為我們所處的境界已經不同。剛開始,我們拋開一切,忘記一切,從本質的角度用對象論去看世界,我們看到的對象是相對孤立的。而后來,我們的抽象思維作用于這個世界,所衍生出來的一系列概念,是我們的抽象能力給這個世界抹上的色彩。就如我們用唯物主義看世界時,剛開始要拋開一切,認為世界只有“可被意識所反映的客觀實在”,而后,這個物質為本的世界在我們的抽象思維中衍生出各種概念。為了讓我們更好的、系統的認識對象論,剛開始,我們拋開一切直取本質,而后來,我們要層層衍生,將拋卻的東西再找回來,在這個“找”的過程中,我們才能領會OO中的各種概念、事物其在哲學意義上是怎么來的。

出處:http://leoo2sk.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
it知識庫:OO真經——關于面向對象的哲學體系及科學體系的探討(上),轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。