編程新手如何理解“面向對象”


先說一點,其實我是不建議新手去“深入”理解面向對象的。所謂“深入”,大概就以“設計模式”為界吧。通常情況下,兩年工作經驗以下的新人,去研究“設計模式”要么是半途而廢(這算是好的),要么就是把自己搞廢了(走火入魔)。

這些年,談“設計模式”的人確實是越來越少了,而且前兩天我看到一個問題:面向對象(OOP)是編程語言發展中的彎路嗎?為什么?

這個有點狠,呵呵。“彎路”倒談不上,只能說現在“面向對象”已經被拉下神壇,回歸常態:不再是“萬物皆對象”的狂熱,而應該是在適合面向對象的地方面向對象

不知道大家是否同意:設計模式本質上是對傳統面向對象“弊端”的一種修補?這個說得深了一點,新手隨便看看就行。

說正事,編程新手應該如何理解“面向對象”?

首先,面向對象仍然是目前最主流、最有效地處理復雜業務邏輯的手段。大家不要矯枉過正,聽有些家伙叫囂“面向對象已死”啥的。那么多以前不支持面向對象的語言(比如php/JavaScript)都在盡力的往對象上面靠,就是一個明證。當然,學習面向對象,最好還是通過純粹的、原生支持面向對象的語言,比如C#和Java,強烈建議通過JavaScript學習面向對象——太殘太擰太傷心……

其次,大家要明白“面向對象”要解決的問題,或者它使用的場景。面向對象並不適用於你在學習各種語言語法時寫的那些Demo程序(比如“冒泡排序”“圖書/課程管理系統”啥的),甚至於大多數的小型開發項目(比如普通的企業網站、個人博客)都不適合。面向對象適合的是那些業務邏輯復雜(其實用“繁雜”更恰當一些)的大型項目。所謂繁雜,繁指多,雜指亂,項目“雜亂”,可以表現為:功能多改動多,所以代碼量大、開發人員多、開發/維護跨度時間長……

這個我接下來還要繼續講,但大家先一定要有這個意識。不然你老是用“面向對象”套你那幾個小項目,怎么抽象怎么封裝,肯定會越整越暈。小項目里,“面向對象”沒用,體現不出來“面向對象”的那些好處——這也還是為什么我一開始就講“不建議新手去‘深入’理解面向對象”的原因,這個階段,你接觸的項目規模有限,對代碼復雜性的理解有限,很難體會“面向對象”的作用。

最后,我給大家勾勒出理解面向對象的幾個層次,由淺入深,大家可以依次理解。

1、學會面向對象的語法。類的聲明和繼承、接口和抽象類、方法和屬性、訪問修飾符……這個沒啥說的,非常簡單,都應該掌握。

2、想明白為什么會出現“類”。我推薦如何通俗易懂地舉例說明“面向對象”和“面向過程”有什么區別?里匿名用戶的高贊回答,簡單的說,函數太多,要分“類”管理。這就夠了,然后在實際開發工作中,試着把類分好,清晰有條理就可以了。

3、明白“對象”是方法(函數)和數據的組合。因為如果你只停留在第2點的理解上,所有的類其實就是靜態類,所有的方法都是靜態方法。但類的一大特點,就是它自身是包含數據的,而且不同的數據可以造就不同的實例(對象)。你看,直到這個時候,我們才能說面向對象,而不是面向類。

4、開始“繼承”。注意,從這里開始,就可能有陷阱了。繼承實際上帶來了兩個結果:重用和多態。重用非常好理解,子類能夠使用父類所有非私有的屬性和方法嘛,所以很多同學一使用繼承,就奔着“重用”去了。比如狗有四條腿,貓也有四條腿,那就抽象出一個有四條腿的父類:動物……但這樣做的問題是:桌子也有四條腿,咋整?由於事物之間復雜的共性/特性關系,很容易就整出多重繼承出來,比如你開始是這樣構想的:

一切都非常美好,但是,接下來“鴨子”怎么辦?你覺得它應該是禽類,但是請注意,它也是會游泳的(代碼里需要這個功能)。同理,還有公雞,它也可以產肉,又該怎么辦?還有漂亮的畫眉,就是用來觀賞的,咋整?動物越來越多,這個體系就崩潰了……

所以這里其實是可以批評“面向對象”的第一個點,或者層面。但是,永遠不要因為一門技術有這樣那樣的問題,就輕易的放棄。隨着你學習的深入,你可以有更深層次的理解。

5、用組合實現重用,用繼承實現多態。這實際上是對第4條的一次“修補”(注意:不是“顛覆”)。我個人認為,這其實是“設計模式”的基礎或者核心。對於初學者而言,理解到這里就差不多了;要講起來,也非常非常的難了。這幾乎上升到一種“藝術”的范疇了,好吧,飛哥承認,我自己對此的理解——理解可能是理解了,但應用起來還是捉襟見肘,不是很溜。就像你知道了很多公式,一樣解不出一道數學題一樣。

問題在哪里?我稱之為“復雜度守恆”。有的同學或者聽說過“‘面向對象’的設計能夠降低復雜度”……但實際上,並沒有。業務邏輯的復雜度永遠是不可能降低的,除非你改需求;需求就是那樣了,所以復雜度就在哪里了,你怎么降低?無論是面向對象,還是設計模式,和不面向對象編程(比如結構化編程)相比,其本質是把復雜度轉移到類的關系復雜度上。

我感覺我好像又說得深了一點?就再說一點就停,可能有同學知道工廠模式,能夠干掉丑陋的switch...case...,但是,switch...case...這種邏輯,真的消失了嗎?沒有啊!同學,它不過是通過類的繼承和多態實現了呀。你覺得if...else...嵌套非常復雜,但數不清的類的關系一樣復雜啊!

我說這些,如果你是新人,可能根本體會不到。可能if...else...嵌套的復雜都還體會不到,就不用說其他了。所以,就此打住吧。我覺得新人能夠掌握第3個層次,理解到第4個層次,摸到第5個層次的邊,就非常非常不錯了。

 

可能有些同學看了4和5,會覺得:那“面向對象”就確實沒有價值啊!就算是做到了第5個層次,也不過是“轉移”了復雜度而已。既然if...else...的嵌套和子類父類一樣復雜,我干嘛要選擇子類父類這種復雜呢?

Good question!

我能給你最簡單的回答,兩個原因:

1、“人腦”的局限。面對復雜事物,人腦的自然處理方式就是“抽象”和“屏蔽細節”。

假設你現在是一個元帥,要指揮一場戰役,你怎么指揮?是不是只會下達一個簡單的命令:第十四軍必須在15日以前占領23號高地?至於十四軍如何占領這個高地,兵力怎么部署、火力怎么配置、需要什么樣的后勤資源……一堆的細節問題,你是不是只能忽略掉?

2、從“代碼寫給電腦看”到“代碼是給人看”的轉變。

在計算機發展的初期,程序非常的簡單,電腦也無法理解高級的復雜的——實際上就是“類自然語言”的指令,程序員大量的工作是把需求“翻譯”成電腦能夠理解和執行的低級指令,比如石器時代的二進制打孔、匯編和C語言等等,形象的說就是“手把手”的教電腦如何操作,可以具體到“分配32個字節的內存”“存儲到CPU的寄存器”這種粒度。

這種方式原始低效,根本無法滿足日益增長的軟件開發需求,一個最有效對接解決方式就是:把翻譯(編譯)的工作交給電腦自己去做,給程序員騰出時間和精力解決業務邏輯需求。所以,編程語言變得越來越“高級”越來越類似於人類自然語言。

其實,結構化編程的if...else...已經很接近人類語言了,但這還不夠。於是,“面向對象”應運而生。語言是思維的載體:結構化語言,對應的仍然是具體的、一步一步執行性的思維;面向對象,對應的是抽象的、以目標為導向不論細節的的思維!

仍然以戰役指揮為例,面向過程,大概就是:

  1. 32門火炮轟擊地方陣地5分鍾
  2. 16名士兵配合2輛坦克向前沖鋒
  3. 1架直升機提供空中支援
  4. ……

面向對象就是:

第二連占領地方陣地。

怎么占領?第二連自己去實現!

於是很多初學者就接受不了,心里是懸着的,他老是要去想:第二連究竟是怎么占領這個陣地的呢?最關鍵的是,這個實現過程最后還是得他自己去寫,所以他本能的就抗拒,或者說迷糊:進行面向對象的封裝啊抽象啊啥的,脫了褲子放屁,多此一舉嘛!O(∩_∩)O~

 

一不小心又寫了這么多。但是呢,效果怎么樣,我心里也是懸着的。所以,回到之前說的,我還是不建議初學者深究“面向對象”,以后,有了工作經驗有了團隊分工合作接觸了大型項目,自然而然地就會逐漸明白:“面向對象”是被逼出來,而不是設計出來的!這一點,其實非常重要。

 

最后,給大家兩種圖:

還沒有軟裝,等着加海報/壁畫等……

床墊薄了,等着,海綿/棕墊正在路上

 

++++++++++++++++++++

 

飛哥的“一起幫·源棧”全棧培訓,小班教學,拎包入住。

開業酬賓,折上再打折,有興趣的同學加QQ群:729600626,等着你來撩,^_^


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM