面向對象程序設計比傳統的面向過程程序設計更有什麼好處?


貼一段8年前寫的:

假設我們是上帝,要創造世界,因為這個過程太過複雜,無從入手,所以先從一件簡單的事情看起。現在我們要設計一個方法,用於描述狼吃羊這個事情,某隻狼吃了某隻羊,你可以面向過程地吃,eat(狼A, 羊A),也可以面向對象地吃,狼A.eat(羊A)。差別在哪裡?只是寫法有點變化。

好,那麼我們幫上帝模擬整個生物界,這裡面很多東西可以吃,大魚吃小魚,小魚吃蝦米,吃不吃皮,吐不吐骨頭,這個時候再來修改這個eat函數,複雜嗎?eat裡面要判斷很多東西,假如上帝很勤勞,所有代碼都自己設計,那沒關係,沒太大區別,判斷就判斷唄。

假設上帝沒足夠精力來管理整個東西了,雇了一群天使來協助設計,每個人都來修改這個eat函數,當然可以拆分,wolfEatSheep(), tigerEatWolf(),然後在eat裡面判斷參數來分別調用,把函數分下去讓每個人做,可以。

動物不光要做吃這個事情,要能跑能跳,會說會叫,又多了一堆函數,每個裡面都這麼判斷,相當相當的煩。怎麼辦?我們來面向對象一下。

現在開始按照動物拆分,100個天使,每個天使創造一種動物。創造哪種動物,就站在哪種動物的角度考慮問題,我吃的時候怎麼吃,跑的時候怎麼跑,都跟別人無關,這麼一來,每個人就專註多了。每個動物只關注我要怎麼才能活著,不必站在上帝的角度考慮問題。這個過程,是類的劃分過程,也就是封裝的過程。

這時候,上帝覺得自然界光有動物是不行的,還要有植物,剛才說的這些都是動物,植物的特點跟動物有很大區別。假設你是上帝,為每種生物安排衣食住行,那是相當複雜的。偷懶吧,上帝說,植物們,你們自己生長吧,動物們,你們吃喝玩樂吧,假如能達到這個效果,那很省事。

上帝用一個循環來遍歷所有動物,讓他們吃喝玩樂,用另外一個循環讓植物欣欣向榮。動物跟植物為什麼要區別對待?因為它們不是同樣的東西,能做的事情不同。所有動物派生於動物這個基礎類型,從動物這個種類下,又分出各種綱,各種目,各種屬。獅子是哺乳動物,猴子也是,但是獅子是貓科動物,猴子是靈長動物,這就構成了一個倒著的樹狀體系,一層一層形成繼承關係。哺乳動物會餵奶,那麼所有繼承自哺乳動物的,都自動擁有這個特徵。整個這一切,構成了繼承鏈。

假設有一天由於變異出現了新物種,不必勞煩上帝關照,只要鑒別一下它屬於什麼類型,就知道能做什麼事了,它的一舉一動,都必然擁有它所繼承的種類的特徵。

這樣就能描述生物界了嗎?不,還有那麼一些怪胎的存在。你認為哺乳動物都不會飛,那就錯了,因為蝙蝠會飛。蝙蝠會飛是它自身的特性,並非繼承自哺乳動物,但是「飛」這個動作,卻非蝙蝠獨有。如果把「飛」定義成介面,那就很美好了,蝙蝠實現了它的飛行介面,雖然內部實現跟鳥類有所不同,而且這並不影響它的哺乳動物特性。

總之,是否面向對象只是思維方式的不同。做一個軟體,面向對象也能做,不面向對象也能做。我的觀點,如果關注可維護性和協作性,從目前的角度,面向對象是很好的選擇,它很自然,很優雅,優雅得只要打一個「.」,你就能想起來什麼事能做,什麼事不能做。


我記得OO的流行是因為GUI的流行,傳統的面向過程的語言在編寫和設計GUI應用的時候顯得非常的吃力。

將GUI的界面元素抽象為控制項,再使用對象來實現之,比起傳統的面向過程能夠更好的開發和設計GUI的應用程序。

面向對象也只是眾多編程範式中的一種,一般認為面向對象比較適合應用於GUI開發、領域建模。

一個新的編程範式提出和流行並不見得就是各方面都強於之前的,而是因為某些特定的領域出現了一些現有的範式難以解決的問題而已。就像函數式其實非常古老了,最近突然流行起來無非是其天然適合高並發的環境罷了。


說C++易於維護的人,真的做過維護嗎?

從業十多年了, 所有項目中最難維護的就是C++的模塊。 改一個問題至少需要3-4倍的C code 的時間。

原因:

1)面向對象用著好用,真的出問題了很難改.因為你需要從當年代碼中去才想以前寫code人的抽象的方法。不然很難理解。 我覺得只有一些GUI的code好理解, 其他的太噁心了。 從出錯的地方查到真正改錯的地方要找很久。 尤其是號稱用了很多設計模式的, 用的好的還行, 用的不好的,簡直想殺了這幫沒事找事的人,就這點破功能,用的著間接這麼多層的。 改bug的時候,無比懷念C的code。

2)C++很難學,一個長期維護的代碼被不同水平的人一改,真的很難看。。。。


好的OO Design可以提供更佳的易讀性 可維護性, 對大型系統來說尤其有效. 但是好的OO設計並不容易, 甚至更複雜. 所以很多OO的系統反而更難維護和更新. 從語言本身上來講只是支持不支持而已, 比如C和C++. 用C一樣可以用設計出漂亮的OO 比如Linux Kernel, 其實很多OO的理念.


從接觸第一門語言到現在為止已經差不多10年時間了。說下個人的觀點。

一、編程到底是個什麼事物?

編程(程序設計)實際上是一個對現實世界中的事物抽象,並由計算機語言實現的過程。

核心的步驟就包含三個:理解、抽象、實現。

不同的理解思路,會導致完全不同的抽象結果;

不同的抽象結果就會提供各不同的理解。

最後根據理解和抽象,由特定的語言完成時間,但其結果要想完全理解還需要前兩個步驟支撐。

有點像建築中的「房子是什麼,房地產設計,蓋房子」。(推薦《建築的永恆之道》)

二、編程的發展過程到底有哪些?

程序設計的歷史,記得以前知乎上有專門介紹編程的歷史,具體地址忘記了。但可以參考百度百科中《計算機歷史:http://baike.baidu.com/view/17139.htm#5》

按照我的理解大致的幾個主要階段:

1、計算機程序設計歷史前階段;主要是紙帶、存儲器等原始方式。

2、計算機語言初級階段;主要以彙編語言為主,面向的主要內容是「數據存儲+指令集」;

3、計算機廣泛工業語言設計階段;主要以C語言為主的大面積應用,此時由C語言更面向人易懂的方向發展。並且操作系統,編譯器,資料庫軟體開始發展;面向的主要內容是「程序=演算法+數據結構」。此時在計算機軟體設計學科中主要運用的還是「面向過程」的設計思路。

4、計算機語言高級發展階段。主要是一些面向對象語言的出現。主要體現在C++語言的出現。主要面向的內容是「應用=對象+通訊」的方式。甚至很多語言開始「一切皆對象」的設計理念。面向對象的語言主要在該階段得到了大力提倡。因為C++的複雜,Java的出現降低了複雜度,又充分利用了面向對象的特點。讓面向對象的設計更是得到了大面積的推廣和應用,尤其在企業級應用開發中。

5、各類語言頻繁出現的繁榮各階段。各類變成設計語言如面向WEB變成,函數式語言,面向並發的語言,終端設備的編程語言等等;這個階段不好做評論。

三、編程的過程解決的問題有哪些?

1、彙編語言:解決CPU指令集和存儲系統的交互問題,提供「可編程」的能力

2、面向過稱語言:提供小面積的問題解決思路,一個系統的代碼如果不多,通過面向過程思路將系統劃分為多個過程(多個函數+各類數據結構)進行系統設計。提供了初級規模的系統設計問題。

3、面向對象語言:當面向過程面對複雜的系統,複雜的世界時。如何「更好的理解和抽象」編程問題,變得更加重要。通過面向對象語言的特點「封裝、繼承、多態」,讓程序分析和設計能容納更大的編程範圍和系統規模,也讓程序設計人員更好的理解和抽象提供了非常重要的作用。

4、面向**語言:面向WEB,面向高並發,面向切面,函數式語言,終端開發等是在現有程序設計語言基礎上不斷改進,並解決特定領域特定問題的發展衍生;

四、面向對象編程思想的重要性體現是什麼?

大家都知道,面向對象的三大特性「封裝、繼承、多態」,但個人認為其中的「封裝」是面向對象的最核心的特點。

究其原因,主要是「封裝」讓一個人可以理解的系統範圍可以變得更廣,可以讓我們「更好的理解和抽象」我們所看到的世界。

之前一個老師提到面向對象時,提到的是「間接」,我想間接也可以認為是「封裝」的升級版。

而面向對象編程思想的作用,可以看看我們常見的編程原則《見:程序設計的18大原則http://hi.baidu.com/andida591/item/54f8d2dc5e2a9ce1795daafa》,面向對象的思想能更好的指導我們滿足這些原則,從而帶來「可維護性,可擴展性,可理解性」等讓我們能在效率和水平上更加長進的東西。

五、總結一句話

「面向對象」相比「面向過程」帶給我們的是認識和抽象世界的一種更有效的思路」。

以上也是個人的一些總結,沒什麼引經據典,但如果知友想更好的了解計算機程序設計這個行當,還是建議能把計算機的歷史、程序設計的歷史、以及C,C++,Java能學習一遍,更能體會到編程思想在幾門語言中的側重和發展演變原因。


呃,首先不管是面向對象,面向過程,面向組件,函數式都是一種概念。這些概念都是對程序或者說「將任務抽象為計算機可理解的文章的方法」的一種理念。

但是另外一極是,程序的源碼是由人類創造和維護,因此還需要人類認知程度上,可編寫可理解可控制。

比如:函數的概念,如果所有的程序都在一個過程裡面,肯定也是可以的。(提供順序,循環或者遞歸,條件判斷這三個就可以)。但是函數的抽象出來

1,方便重用。在很多地方可以反覆調用該函數。減少了反覆編寫的麻煩。

2,模塊封裝。調用函數,不需要考慮函數內部的實現細節,作為一個調用介面就完成了這個功能。

3,便於人的理解與控制。

由此可見,在函數的基礎上,就可以從最簡單的操作如a++;組件成一個底層的小函數。底層的函數可以進一步封裝組合(按照上面的3種方式,順序,循環/遞歸,條件)成為更大的函數。。。。之後就可以構建出一個複雜無比,功能完善的程序。

至此,都可以順利理解的話。那麼其他新的概念的提出,不過是為了更好的符合上面的要求。

面向對象的方式,相比於面向過程的編程,也是更好的體現了上面3點。面向組件在小程序的層面上滿足上面3點。函數式也是的,它主要是強調無副作用的滿足上面3點。

好了,上面的都理解了,那麼這個問題,也可以說理解了,或者說已經不重要了。


面向對象,面向過程,都屬於 imperative 。沒什麼本質區別。只不過前者對變數的訪問許可權做了一些限制。除了最早期那幫用 Fortran 的數學家,很少有人真的完全不顧變數的意義隨意訪問。所以純面向過程應該從來就不多。


可以參考這個問題中的回答

http://www.zhihu.com/question/20603416


題主問的問題是:面向對象程序設計比傳統的面向過程程序設計更有什麼好處?

那我就就事論事,不扯其他的,回答好處在哪裡。

1、通過重用提高產品質量和生產率

在面向對象技術中可以通過「重用」以前的項目中經過精心測試的對象,或者由他人編寫、測試、維護的對象類來構建系統,這個大大降低了開發的成本,也確保了良好的產品質量。

2、使系統具有良好的易修改性和易擴展性

通過封裝可以隱蔽對象中的屬性和方法,因為改變對象中的變數和方法時,不會影響到其他部分,從而修改老的類。此外繼承是面向對象技術的重要特性,在創建一個新的對象時,通過繼承老的類,可以極大的節省開發的時空開銷。

3、保證系統的可靠性和安全性


從業幾年,接觸過腳本語言、面向過程、面向對象……雖然稱不上Master,但還算對這個問題進行過很久的思考的。

面向對象程序設計,以及其23種設計模型,其核心最有價值的地方其實是——避免了豬隊友。

面向對象編程哪怕你生搬硬套設計模式,最後都不會爛到哪裡去。一堆框框約束著你(當然這就是知乎上Java被人黑出翔的理由),你做不了很多事,也做不壞很多事。

但是面向過程編程就不同了。我承認C語音的靈活性非常高。而靈活的代價就是很容易搞好,也很容易搞壞。它適合高水平的幾個Geeker,但一旦你隊友有10%水平不濟,你將痛不欲生,欲仙欲死,死去活來……

至於更接近自然之類的說法,其實我感覺只是個表象。任何語言,哪怕腳本語言,JS都還有個Knockout框架把它變成面向對象的呢。對象化思想不一定是萬金油,很多解決方案都不一定適用。但面向對象編程確實將程序設計變得有模板可循。適合大型項目。


1)符合現實抽象,便於理解:只是看類的名字你就可以猜到它有哪些方法了

2)良好的封裝,減少了耦合性,同樣減少了理解的成本:你不需要知道對你沒有的信息

3)耦合性弱,聚合性強,因此可以很好地重用

4)可以很容易地進行功能的擴展(繼承)和功能的修正(覆蓋)

5)設計圖確實好畫很多了...

6)對於大型系統,可以比較地架構/設計,而不至於項目混亂


說句沒有什麼幫助的老實話,面向對象編程才是「傳統」的編程,面向過程的編程要去博物館才看得到,也許提問者可以考慮更新一下教科書?這個問題如果改成「Functional Programming比傳統的面向對象編程有什麼好處「可能能吸引更多的回答者。

吐槽完畢。基本上面向對象編程強調「封裝」,「繼承「和「多態」。數據和與數據相關的操作被包裝成對象(嚴格的說是「類」),每一種對象是相對完整和獨立的。對象可以有派生的類型,派生的類型可以覆蓋(或重載)原本已有的操作。所有的這些,是為了達成更好的內聚性,即一種對象做好一件(或者一類相關的)事情,對象內部的細節外面世界不關心也看不到;以及降低耦合性,即不同種類的對象之間相互的依賴儘可能降低。而所有的這些,都有助於達成一個崇高的目標,就是可復用性。別人寫出來的東西,你可以簡簡單單拿過來用,還可以加以發展,這不是一個很美好的世界嗎?對軟體工程這灘著名的泥潭來講,可復用性就像一個不可或缺的救生圈。

至於面向過程編程……還是不要再挖墳了。


The problem with object-oriented languages is they"ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.


1,更接近自然事物的描述方式,容易理解

2,繼承封裝多態,使得程序便於管理和擴展

3,對大型的項目有幫助,小型的講求運行效率的,面向過程更好一點


c也是面象對象的,c++封裝不過是功能的聚合,真正的面向過程編程是協程和線程。


那些年搞不懂的高深術語——依賴倒置?控制反轉?依賴注入?面向介面編程

那些年,空氣中彷彿還能聞到漢唐盛世的餘韻,因此你決不允許自己的臉上有油光,時刻保持活力。然而,你一定曾為這些「高深術語」感到過困擾。也許時至今日,你仍對它們一知半解。不過就在今天,這一切都將徹底改變!我將帶領你以一種全新的高清視角進入奇妙的編程世界,領略涵泳在這些「高深術語」中的活潑潑的地氣,以及翩躚於青萍之末的雲水禪心。

·內聚

內聚,通俗的來講,就是自己的東西自己保管,自己的事情自己做。

經典理論告訴我們,程序的兩大要素:一個是數據(data),一個是操作(opration)。而 PASCAL之父Nicklaus Wirth則進一步提出了「程序 = 數據結構 + 演算法」的著名公式。雖然提法上有所差異,但是其根本內涵卻是一致的,微妙的差別在於,「數據 + 操作」是微觀的視域,「數據結構 + 演算法」則是中觀的視域。而在宏觀的視域下,我認為「程序 = 對象 + 消息」。對象是什麼?對象就是保管好自己的東西,做好自己的事情的程序模塊——這就是內聚!傳統的面向過程編程方法由於割裂了數據結構和演算法,使得軟體的內聚性普遍低迷,曾一度引發了軟體危機。試想,大家都自己的東西不好好保管,自己的事情也不好好做,不引發危機才怪呢!當然,對象的內聚只是內聚的一個層次,在不同的尺度下其實都有內聚的要求,比如方法也要講內聚,架構也要講內聚。

《周易·彖傳》中講「乾道變化,各正性命,保合太和,乃利貞」,就是要求每一個個體因循著各自的稟賦而努力成就各自的品性,然後各自保全,彼此和合,最終達成宇宙的完滿狀態。《論語·憲問》中,子路問君子。子曰:「修己以敬。」曰:「如斯而已乎?」曰:「修己以安人」,更是明確的教導我們要不斷提高自身的內聚性,最大限度地減少給他人造成的麻煩,從而達到安人、安百姓、安天下的目標。我想,成長的過程就是一個不斷提升內聚的過程。「自己的東西自己保管,自己的事情自己做」,這些孩提時代的教誨,放到今天仍能讓不少「大人」臉紅不已。太多的人保管不好自己的「東西」,保管不好自己的身體,保管不好自己的婚姻,更保管不好自己如蛛絲般震顫飄蕩的狂亂的心。至於做好自己的事情,則更是惘然,甚至很多人連自己的事情是什麼都搞不清楚,因此渾渾噩噩,飽食終日。內聚,是一個值得我們好好反思的問題。

·依賴·耦合

在面向對象編程中,對象自身是內聚的,是保管好自己的數據,完成好自己的操作的,而對外界呈現出自己的狀態和行為。但是,沒有絕對的自力更生,對外開放也是必要的!一個對象,往往需要跟其他對象打交道,既包括獲知其他對象的狀態,也包括仰賴其他對象的行為,而一旦這樣的事情發生時,我們便稱該對象依賴於另一對象。只要兩個對象之間存在一方依賴一方的關係,那麼我們就稱這兩個對象之間存在耦合。 比如媽媽和baby,媽媽要隨時關注baby的睡、醒、困、哭、尿等等狀態,baby則要仰賴媽媽的餵奶、哄睡、換紙尿褲等行為,從程序的意義上說,二者互相依賴,因此也存在耦合。首先要說,耦合是必要的。我們來看以下這個實驗。

【王陽明與山中之花

View Code

由於王陽明這個對象不依賴山花這個對象,又沒有其他的方式來獲知山花的盛開狀態,所以他要麼選擇不說,要麼瞎說,但不說編譯是通不過,而瞎說作為王陽明來講也是通不過的,所以這個系統是無法成立的。要想系統成立,必須要這樣寫:

public bool AdmireFlowers()
{
return flower.IsBloomed; ;
}

無論這個山花對象是怎麼來的,作為參數傳入還是作為屬性設置、還是在內部構造出來,總之,王陽明與山花之間發生了依賴,二者之間產生了耦合。 當然,這是一個很淺顯的問題。有趣的是王陽明對此事的看法:「你未看花時,花與你同寂;你來看花,花於你則一時分明起來。可見心外無物!」王陽明講的是對的!「心外無物」翻譯技術語言是這樣的:不存在耦合的兩個對象必然拿不到對方的引用!

·耦合度·解耦和

耦合的程度就是耦合度,也就是雙方依賴的程度。上文所說的媽媽和baby就是強耦合。而你跟快遞小哥之間則是弱耦合。一般來說耦合度過高並不是一件好事。就拿作為IT精英的你來說吧,上級隨時敦促你的工作進度,新手頻繁地需要你指導問題,隔三差五還需要參加酒局飯局,然後還要天天看領導的臉色、關注老婆的心情,然後你還要關注代碼中的bug 、bug、bug,和需求的變化、變化、變化,都夠焦頭爛額了,還猝不及防的要關注眼睛、頸椎、前列腺和頭髮的狀態,然後你再炒個股,這些加起來大概就是個強耦合了。從某種意義上來說,耦合天生就與自由為敵,無論是其他對象依賴於你,還是你依賴其他對象。比如有人嗜煙、酗酒,你有多依賴它們就有多不自由;比如有人家裡生了七八個娃,還有年邁的父母、岳父母,他們有多依賴你,你就有多不自由。所以老子這樣講:「五音令人耳聾,五色令人目盲,馳騁狩獵令人心發狂,難得之貨令人行妨。」盧梭也是不無悲涼的說「人生而自由,卻又無往而不在枷鎖中」。因此,要想自由,就必須要降低耦合,而這個過程就叫做解耦和。

·依賴倒置(Dependence Inversion Principle)

解耦和最重要的原則就是依賴倒置原則:

高層模塊不應該依賴底層模塊,他們都應該依賴抽象。抽象不應該依賴於細節,細節應該依賴於抽象。

《資本論》中都曾闡釋依賴倒轉原則——在商品經濟的萌芽時期,出現了物物交換。假設你要買一個IPhone,賣IPhone的老闆讓你拿一頭豬跟他換,可是你並沒有養豬,你只會編程。所以你找到一位養豬戶,說給他做一個養豬的APP來換他一頭豬,他說換豬可以,但是得用一條金項鏈來換——所以這裡就出現了一連串的對象依賴,從而造成了嚴重的耦合災難。解決這個問題的最好的辦法就是,買賣雙發都依賴於抽象——也就是貨幣——來進行交換,這樣一來耦合度就大為降低了。

再舉一個編程中的依賴倒置的例子。我們知道,在通信中,消息的收發和消息的處理往往密不可分。就一般的通信框架而言,消息的收發通常是已經實現了的,而消息的處理則是需要用戶來自定義完成的。先看一個正向依賴的例子:輕量級通信引擎StriveEngine。tcpServerEngine是StriveEngine.dll提供通信引擎,它發布有一個MessageReceived事件。假設我定義了一個CustomizeHandler類來用於消息處理,那麼CustomizeHandler的內部需要預定tcpServerEngine的MessageReceived事件,因此customizeHandler依賴於tcpServerEngine,這就是一個普通的依賴關係,也就是高層模塊依賴於低層模塊。

而ESFramework通信框架應用了依賴倒轉原則。ESFramework定義了一個IcustomizeHandler介面,用戶在進行消息處理時,實現該介面,然後將其注入到rapidPassiveEngine客戶端通信引擎之中。

View Code

很明顯,相比於上一個例子,這裡的依賴關係變成了rapidPassiveEngine依賴於customizeHandler,也就是說依賴關係倒置了過來,上層模塊不再依賴於底層模塊,而是它們共同依賴於抽象。rapidPassiveEngine依賴的是IcustomizeHandler介面類型的參數,customizeHandler同樣是以實現的介面的方式依賴於IcustomizeHandler——這就是一個依賴倒置的典範。

·控制反轉(Inversion of Control)

控制反轉跟依賴倒置是如出一轍的兩個概念,當存在依賴倒置的時候往往也存在著控制反轉。但是控制反轉也有自己的獨特內涵。

首先我們要區分兩個角色,server 跟 Client,也就是服務方和客戶方。提供服務端的一方稱為服務方,請求服務的一方稱為客戶方。我們最熟悉的例子就是分散式應用的C/S架構,服務端和客戶端。其實除此之外,C/S關係處處可見。比如在TCP/IP協議棧中,我們知道,每層協議為上一層提供服務,那麼這裡就是一個C/S關係。當我們使用開發框架時,開發框架就是作為服務方,而我們自己編寫的業務應用就是客戶方。當Client調用server時,這個叫做一般的控制;而當server調用Client時,就是我們所說的控制反轉,同時我們也將這個調用稱為「回調」。控制反轉跟依賴倒置都是一種編程思想,依賴倒置著眼於調用的形式,而控制反轉則著眼於程序流程的控制權。一般來說,程序的控制權屬於server,而一旦控制權交到Client,就叫控制反轉。比如你去下館子,你是Client餐館是server。你點菜,餐館負責做菜,程序流程的控制權屬於server;而如果你去自助餐廳,程序流程的控制權就轉到Client了,也就是控制反轉。

控制反轉的思想體現在諸多領域。比如事件的發布/ 訂閱就是一種控制反轉,GOF設計模式中也多處體現了控制反轉,比如典型的模板方法模式等。而開發框架則是控制反轉思想應用的集中體現。比如之前所舉的ESFramework通信框架的例子,通信引擎回調用戶自定義的消息處理器,這就是一個控制反轉。以及ESFramework回調用戶自定義的群組關係和好友關係,回調用戶自定義的用戶管理器以管理在線用戶相關狀態,回調用戶自定義的登陸驗證處理,等等不一而足。再比如與ESFramework一脈相承的輕量級通信引擎StriveEngine,通過回調用戶自定義的通信協議來實現更加靈活的通信。

由此我們也可以總結出開發框架與類庫的區別:使用開發框架時,框架掌握程序流程的控制權,而使用類庫時,則是應用程序掌握程序流程的控制權。或者說,使用框架時,程序的主循環位於框架中,而使用類庫時,程序的主循環位於應用程序之中。框架會回調應用程序,而類庫則不會回調應用程序。ESFramework和StriveEngine中最主要的對象都以engine來命名,我們也可以看出框架對於程序主循環的控制——它會為你把握方向、眼看前方、輕鬆駕馭!

·依賴注入(Dependency Injection)

  依賴注入與依賴倒置、控制反轉的關係仍舊是一本萬殊。依賴注入,就其廣義而言,即是通過「注入」的方式,來獲得依賴。我們知道,A對象依賴於B對象,等價於A對象內部存在對B對象的「調用」,而前提是A對象內部拿到了B對象的引用。B對象的引用的來源無非有以下幾種:A對象內部創建(無論是作為欄位還是作為臨時變數)、構造器注入、屬性注入、方法注入。後面三種方式統稱為「依賴注入」,而第一種方式我也生造了一個名詞,稱為「依賴內生」,二者根本的差異即在於,我所依賴的對象的創建工作是否由我自己來完成。當然,這個是廣義的依賴注入的概念,而我們一般不會這樣來使用。我們通常使用的,是依賴注入的狹義的概念。不過,直接陳述其定義可能會過於詰屈聱牙,我們還是從具體的例子來看。

  比如OMCS網路語音視頻框架,它實現了多媒體設備(麥克風、攝像頭、桌面、電子白板)的採集、編碼、網路傳送、解碼、播放(或顯示)等相關的一整套流程,可以快速地開發出視頻聊天系統、視頻會議系統、遠程醫療系統、遠程教育系統、網路監控系統等等基於網路多媒體的應用系統。然而,OMCS直接支持的是通用的語音視頻設備,而在某些系統中,需要使用網路攝像頭或者特殊的視頻採集卡作為視頻源,或者其它的聲音採集設備作為音頻源,OMCS則提供了擴展介面——用戶自己實現這個擴展的介面,然後以「依賴注入」的方式將對象實例注入到OMCS中,從而完成對音、視頻設備的擴展。

「依賴注入」常常用於擴展,尤其是在開發框架的設計中。從某種意義上來說,任何開發框架,天生都是不完整的應用程序。因此,一個優秀的開發框架,不僅要讓開發者能夠重用這些久經考驗的的卓越的解決方案,也要讓開發者能夠向框架中插入自定義的業務邏輯,從而靈活自由地適應特定的業務場景的需要——也就是說要具備良好的可擴展性。比如上面提到的OMCS網路語音視頻框架可應用於音、視頻聊天系統、視頻會議系統、遠程醫療系統、遠程教育系統、網路監控系統等等基於網路多媒體的應用系統;以及ESFramework通信框架能夠應用於即時通訊系統,大型多人在線遊戲、在線網頁遊戲、文件傳送系統、數據採集系統、分散式OA系統等任何需要分散式通信的軟體系統中——這種良好的擴展性都與「依賴注入」的使用密不可分!

·面向介面編程

談到最後,「面向介面編程」已經是呼之欲出。無論是依賴倒置、控制反轉、還是依賴注入,都已經蘊含著「面向介面編程」的思想。面向介面,就意味著面向抽象。作為哲學範疇而言,規定性少稱為抽象,規定性多稱為具體。而介面,就是程序中的一種典型的「抽象」的形式。面向抽象,就意味著面向事物的本質規定性,擺脫感性雜多的牽絆,從而把握住「必然」——而這本身就意味著自由,因為自由就是對必然的認識。

也許以上的這段論述太過「哲學」,但是「一本之理」與「萬殊之理」本身就「體用不二」——總結來看,依賴倒置、控制反轉、依賴注入都圍繞著「解耦和」的問題,而同時自始至終又都是「面向介面編程」的方法——因此,「面向介面編程」天生就是「解耦和」的好辦法。由此也印證了從「抽象」到「自由」的這一段範疇的辯證衍化。

「面向對象」與「面向介面」並非兩種不同的方法學,「面向介面」其實是「面向對象」的內在要求,是其一部分內涵的集中表述。我們對於理想軟體的期待常被概括為「高內聚,低耦合」,這也是整個現代軟體開發方法學所追求的目標。面向對象方法學作為現代軟體開發方法學的代表,本身就蘊含著「高內聚,低耦合」的思想精髓,從這個意義上來說,「面向對象」這個表述更加側重於「高內聚」,「面向介面」的表述則更加側重於「低耦合」——不過是同一事物的不同側面罷了。

除此之外,我們也能從「面向介面編程」的思想中得到「世俗」的啟迪——《論語》裡面講,不患無位,患所以立;不患人之不己知,患其不能也——就是教導我們要面向「我有沒有的本事?」、「我有沒有能力?」這樣的介面,而不是面向「我有沒有搞到位子?」、「別人了不了解我?」這樣的具體。依我看,這是莫大的教誨!


可維護性!可維護性!可維護性!可維護性!

Grady Booch:我對OO編程的目標從來就不是復用。相反,對我來說,對象提供了一種處理複雜性的方式。這個問題可以追溯到亞里士多德:您把這個世界視為過程還是對象?在OO興起運動之前,編程以過程為中心--例如結構化設計方法。然而,系統已經到達了超越其處理能力的複雜性極點。有了對象,我們能夠通過提升抽象級別來構建更大的、更複雜的系統--我認為,這才是面向對象編程運動的真正勝利


面向對象,就為了更好的,更好的,更好的解決軟體需求不斷變化產生的問題! 如何解決? 用介面去封裝變化的地方!

簡簡單單的問題,大家好像都說不清楚!


前兩天看到一句話:編程,就是控制複雜性。


面向對象可閱讀性高,但是代碼量大。

面向過程 可以實現 面向對象能實現的所有功能,也具有復用好處。個人覺得都一樣,只是對整個問題定義和分析過程中,角度的不同而造成的錯覺。其實class和struct是一樣的,class封裝的function和用c寫的function一樣,慢慢的分析問題的時候從橫縱兩個方向考慮。推薦看看nginx源碼(c實現), 還有STL源碼(c++)。(當然這裡面有很多語言相關&<編譯器&>的不同)


推薦閱讀:

面向對象編程是否是從根本上反模塊化且反並行的?為什麼?
面向對象編程的弊端是什麼?

TAG:編程 | 計算機 | C編程語言 | 面向對象編程 | C | 面向過程 |