昨天晚上在知乎看到這個問題,一時還真說不太清。之前一直用JAVA和Android做開發,近期在維護一個老的項目,是用VB開發的,代碼超過十個年頭了,接觸了一段時間。對面向過程和面向對象都有所涉及,在這里這個小結(有些是在網上收集的)
自己的理解:
面向過程是一種以事件為中心的編程思想,以功能(行為)為導向,按模塊化的設計,就是分析出解決這個問題所須要的步驟,然后用函數把這些步驟一步一步實現,實現的時候一個一個依次調用就能夠了
面向對象是一種以事物為中心的編程思想,以數據(屬性)為導向,將具有同樣一個或者多個屬性的物體抽象為“類”,將他們包裝起來;而有了這些數據(屬性)之后,我們再考慮他們的行為(對這些屬性進行如何的操作),是把構成問題的事物分解成各個對象,建立對象的目的不是為了完畢一個步驟,而是為了描寫敘述某個事物在整個解決這個問題的步驟中的行為。面向對象的技術,是一種以對象為基礎,以事件或消息來驅動對象運行處理的程序設計技術。它具有封裝性,繼承性以及多態性。
知乎網友rlei;
面向對象編程強調“封裝”,“繼承“和“多態”。數據和與數據相關的操作被包裝成對象(嚴格的說是“類”),每一種對象是相對完整和獨立的。對象能夠有派生的類型,派生的類型能夠覆蓋(或重載)原本已有的操作。全部的這些,是為了達成更好的內聚性,即一種對象做好一件(或者一類相關的)事情,對象內部的細節外面世界不關心也看不到;以及減少耦合性,即不同種類的對象之間相互的依賴盡可能減少。而全部的這些,都有助於達成一個崇高的目標,就是可復用性。別人寫出來的東西,你能夠簡簡單單拿過來用,還能夠加以發展,這不是一個非常美好的世界嗎?
精講
面向過程就是分析出解決這個問題所須要的步驟,然后用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就能夠了。面向對象是把構成問題事務分解成各個對象,建立對象的目的不是為了完畢一個步驟,而是為了描敘某個事物在整個解決這個問題的步驟中的行為。
面向過程
面向過程的程序設計是一種自上而下的設計方法,設計者用一個main函數概括出整個應用程序須要做的事,而main函數由對一系列子函數的調用組成。對於main中的每個子函數,都又能夠再被精煉成更小的函數。反復這個過程,就能夠完畢一個過程式的設計。其特征是以函數為中心,用函數來作為划分程序的基本單位,數據在過程式設計中往往處於從屬的位置。
面向過程式設計的長處是易於理解和掌握,這樣的逐步細化問題的設計方法和大多數人的思維方式比較接近。
然而,過程式設計對於比較復雜的問題,或是在開發中需求變化比較多的時候,往往顯得力不從心。這是由於過程式的設計是自上而下的,這要求設計者在一開始就要對須要解決的問題有一定的了解。在問題比較復雜的時候,要做到這一點會比較困難,而當開發中需求變化的時候,曾經對問題的理解或許會變得不再適用。其實,開發一個系統的過程往往也是一個對系統不斷了解和學習的過程,而過程式的設計方法忽略了這一點。
在面向過程式設計的語言中,一般都既有定義數據的元素,如C語言中的結構,也有定義操作的元素,如C語言中的函數。這樣做的結果是數據和操作被分離開,easy導致對一種數據的操作分布在整個程序的各個角落,而一個操作也可能會用到非常多種數據,在這樣的情況下,對數據和操作的不論什么一部分進行改動都會變得非常困難。
在面向過程式設計中,main()函數處於一個非常重要的地位。設計者正是在main()函數中,對整個系統進行一個概括的描寫敘述,再以此為起點,逐步細化出整個應用程序。然而,這樣做的一個后果,是easy將一些較外延和易變化的邏輯(比方用戶交互)同程序的核心邏輯混淆在一起。如果我們編寫一個圖形界面的計算器程序和一個命令行界面的計算器程序,能夠想象這兩個版本號的main()函數會有非常大的差異,由此衍生出來的程序非常有可能也會迥然不同,而這兩個版本號的程序本應該有非常大部分能夠共用才對。
面向過程式設計另一個問題就是其程序架構的依賴關系問題。一個典型的過程式程序往往如Figure 1所看到的:

Figure 1
圖中的箭頭代表了函數間的調用關系,也是函數間的依賴關系。如圖所看到的,main()函數依賴於其子函數,這些子函數又依賴於更小的子函數,而在程序中,越小的函數處理的往往是細節實現,這些詳細的實現,又經常變化。這種結果,就是程序的核心邏輯依賴於外延的細節,程序中本來應該是比較穩定的核心邏輯,也由於依賴於易變化的部分,而變得不穩定起來,一個細節上的小小修改,也有可能在依賴關系上引發一系列變動。能夠說這種依賴關系也是過程式設計不能非常優點理變化的原因之中的一個,而一個合理的依賴關系,應該是倒過來,由細節實現依賴於核心邏輯才對。
面向對象設計
面向對象是一種自下而上的程序設計方法。不像過程式設計那樣一開始就要用main概括出整個程序,面向對象設計往往從問題的一部分着手,一點一點地構建出整個程序。面向對象設計以數據為中心,類作為表現數據的工具,是划分程序的基本單位。而函數在面向對象設計中成為了類的接口。
面向對象設計自下而上的特性,同意開發人員從問題的局部開始,在開發過程中逐步加深對系統的理解。這些新的理解以及開發中遇到的需求變化,都會再作用到系統開發本身,形成一種螺旋式的開發方式。(在這樣的開發方式中,對於已有的代碼,常須要運用Refactoring技術來做代碼重構以體現系統的變化。)
和函數相比,數據應該是程序中更穩定的部分,比方,一個網上購物程序,不管怎么變化,大概都會處理貨物、客戶這些數據對象。只是在這里,僅僅有從抽象的角度來看,數據才是穩定的,假設考慮這些數據對象的詳細實現,它們甚至比函數還要不穩定,由於在一個數據對象中增減字段在程序開發中是常事。因此,在以數據為中心構建程序的同一時候,我們須要一種手段來抽象地描寫敘述數據,這樣的手段就是使用函數。在面向對象設計中,類封裝了數據,而類的成員函數作為其對外的接口,抽象地描寫敘述了類。用類將數據和操作這些數據的函數放在一起,這能夠說就是面向對象設計方法的本質。
在面向對象設計中類之間的關系有兩種:客戶(Client)關系和繼承(Inheritance)關系。客戶關系如Figure 2所看到的,表示一個類(Client)會使用到還有一個類(Server)。一般將這樣的關系中的Client類稱為client,Server類稱為 服務器 。

Figure 2
繼承關系如Figure 3所看到的,表示一個類(Child)對還有一個類(Parent)的繼承。一般將這樣的關系中的Parent類稱為父類,Child類稱為子類。

Figure 3
面向對象設計的過程就是將各個類按以上的兩種關系組合在一起,這兩種關系都很easy,只是組合在一起卻能提供強大的設計能力。以下介紹怎樣利用這兩種關系來划分程序的不同模塊。
在非常多應用中,我們都須要將數據 存儲 到數據庫中。一個常見的解決手段是使用分層的方法,將程序分為應用層和 存儲 層,Figure 4中是這樣的方法一個不太成熟的設計:

Figure 4
Application代表應用層的邏輯,DB代表了數據庫訪問的邏輯,在這個設計中,Application直接調用了DB的服務來將數據存儲到數據庫中。這樣做的缺點是Application對DB有了依賴關系,一旦DB有了不論什么變化,Application都有可能會受其影響須要修改。當然,假設僅僅是兩個類的話,這樣的依賴關系根本算不上什么問題,然而,我們有理由相信,應用層和存儲層都會由不僅僅一個類組成,並都有一定的復雜度,這時它們之間的這樣的依賴關系就會讓人頭痛了。當程序的模塊越來越多,假設不限制它們之間的聯系,那模塊間的依賴、程序的復雜度和開發維護的難度都會成指數上升。
所幸的是引入面向對象中的繼承關系,我們能夠解決這一問題,如圖Figure 5所看到的:

Figure 5
Persistence是一個接口,其包括了Application存儲所需用到的服務。DB實現了這個接口,Application則調用Persistence中的服務來存儲數據,兩者都僅僅依賴於Persistence。這樣,Application到DB的依賴關系被Persistence這個接口切斷了。由於接口中僅僅包括了服務,也就是成員函數的聲明,而不包括不論什么數據和函數的實現,所以Persistence接口的內容會非常easy。在Persistence不變的情況下,Application和DB這兩個模塊都能夠自由地進行改動而不影響到對方。就這樣,通過在中間插入接口的方法,程序的模塊被划分開,依賴關系也變得easy管理的多。
假設從還有一個角度來看Figure 4中的設計,應用層是程序的核心部分,而存儲層則能夠看成是實現的細節,這個設計犯了和過程式設計相同的錯誤,即核心邏輯依賴於詳細的實現細節,這樣,當細節變化時,核心邏輯也會受到影響:假如,當我們須要將數據改存到文件或文件夾服務中時,依照Figure 4中的設計Application模塊就難免受到影響。在Figure 5的設計中則沒有這一問題:這里我們能夠把Application和Persistence看成是程序的核心邏輯,而Persistence接口的實現(DB)能夠看成是程序的細節實現,其依賴關系是細節依賴於核心,當細節變化時核心不會受其影響,這才是一個穩定的依賴關系。遵從這一設計,我們能夠在不影響程序核心的情況下,為程序加入或更改存儲類型,如Figure 6所看到的:

Figure 6
這里值得注意的是Persistence和Application被划分到了一起,這是由於Persistence中的服務都是依據Application中的需求制定出來的,Persistence和Application的關系比起它和其子類的關系更加緊密。將接口和其調用者放入一個模塊是一個常見的做法,當然,也能夠將接口單獨划分為一個模塊,這通常是在有多個不同的調用模塊依賴於該接口,或不同模塊間須要更清晰的分離時才這樣做。