一起幫裡有人問“物件導向”的問題。但我建立“一起幫”的目的是幫人解決“具體的”“實務性的”問題,“物件導向”太過於抽象,所以沒批准釋出。後來在QQ群裡討論,看他們七嘴八舌鬧得慌,突然有一種“多情應笑我,早生華髮”的蕭瑟之感。
一轉眼,我學程式設計都已經十年了。
十年之前,“物件導向”火得一塌糊塗。
十年之後,“物件導向”,沒想到,還是這樣雲裡霧裡……
回頭想想,之所以雲裡霧裡,我認為一個很大的原因:我們把“物件導向”神話了。
我今天,就想損一點兒,來把“物件導向”拉下神壇吧。O(∩_∩)O~
我現在都還記得,那時候炫耀自己的專案,“純物件導向開發”……一個“純”字,頓時逼格滿滿。現在想來,那時候說話確實不走腦子。“純物件導向”,還有“不純”的麼?“不純”的是什麼?是雜質,是渣滓?是那些if...else...,是不是應該被剔除?問題是,你剔除了if...else ...,你專案裡還能剩下些什麼?
不知道大家以前有沒有想過這個問題?
我覺得這是一個好問題。“純物件導向”這種說法背後折射出來的,就是把“物件導向”和“程式導向”對立化,從而把“物件導向”人為拔高人為神話。
因為最近動了做培訓來推廣一起幫的念頭,我會這樣來思考這個問題:假如我是老師,我會怎麼和同學們講解“物件導向”?“繼承”“封裝”……No,No,No,那是以後的事。事實上,很長一段時間,我就是被這些東西搞暈了,而沒能觸及到“物件導向”的本質。
我覺得,一步一步由淺入深的理解“物件導向”,正確的姿勢應該是這樣的:
首先,同學們已經理解了方法/函式,明白為了程式碼的重用,我們需要一個又一個的函式。
那麼,假設我們有一個專案,十萬行程式碼(這其實就是微型專案),按一個函式平均50行計算,就會有2000個函式!好,問題來了,2000個函式啊,別說你記住了,你先想想,你咋命名?呵呵。
所以,一定得想辦法,把他們“歸類”(大家注意這個“類”字):這50個函式,都是幹這事兒的;那50個函式,都是幹那事兒的……分門別類之後,2000個函式,50個類,這樣,是不是有條理得多,清晰得多了呢?然後,呼叫一個方法的時候,先找到類,再找這個類下面的函式,是不是更流暢一些?比如:Blog.Publish(),Comment.Publish(),Blog.Agree(),Comment.Agree()……你看,也不用擔心“重名”了。
這才是對“類”最基本最入門的理解——然而,很多同學,恰恰是缺乏這種最基本的理解,或者理解得不夠深入,就直接奔那些“高大上”的概念去了。從而,在開發過程中整出很多莫名其妙的“么蛾子”來。
可能有些同學不服氣,“我怎麼就理解得不夠深入啦”,“這還需要這麼深入理解”?或者,還有一些同學,要教育教育我,“你這個理解太初淺了”,“引入‘物件導向’,是為了‘重用’‘抽象’”,“來來來,我給你講講‘設計模式’,高階貨!”……
這就是問題所在!有些同學,用了一堆的“高階貨”,把本來複雜的程式搞得“更復雜”了。於是,有了所謂“濫用”,“濫用繼承”“濫用設計模式”“濫用……”我想,有過一定開發經驗的同學一定聽說過甚至見識過這種“濫用”的,夠酸爽吧?哈哈。那麼,怎麼才算“濫用”,怎麼才能避免“濫用”?
其核心就在於理解一點:物件導向(其實包括所有針對“企業級應用”開發的思路策略),核心目的都是“降低系統的複雜度”,注意:降低,降低,降低,而不是“增加”系統的複雜度。業務需求本身已經夠複雜了,就不要再給程式碼裡“添亂”了。
請注意,這裡的“複雜”,通常指的是“繁多”“雜亂”“無序”,人腦難以應付。怎麼解決這個問題呢?無它,歸類而已。
好了,回到“物件導向”,我們已經把函式進行了歸類,感覺上舒服多了。然而,當程式碼量進一步膨脹,達到100萬級的時候,就是類,也有500個了,我們的腦子還是不夠用了。這時候,我們就會問:可不可以把這些類再進一步的歸類呢?
當然可以,於是就有了“繼承”;在“繼承”的基礎上,又有了“多型”;有了“多型”,就有了“設計模式”……
這些東西這篇部落格我都不想講,一篇部落格也講不了——太龐大了。
那我想講的是什麼?
是順序,是目的。
是先有方法函式,然後才有類;是有了類,然後才有了繼承……
或者,更準確的說:是先有了一堆一堆多得讓人抓狂的方法函式,才有了類;是先有了一堆一堆多得讓人抓狂的類,才有了繼承……
更本質的說法:是先有了問題,然後才有解決方案。
而我們使用各種工具方法的目的,是為了解決問題。
這十年的程式設計生涯,我其實走得比較順。(比TM的搞裝潢強太多了!)如果一定要說“走了什麼彎路”,也就是在“物件導向”(以及衍生出來的種種,譬如“設計模式”)上面。
我想,最大的問題就在於:一開始,“物件導向”這玩意兒就是被“灌”進腦子裡的,而且你還被不停的灌輸它好很好灰常好——但究竟怎麼個好法,卻很少有人能說得清楚。所以一直暈乎暈乎的,不明覺厲。而且你會自然而然的產生一種心理:物件導向好,沒有物件導向就是不好的。
這當然是不對的。
你可以把“物件導向”當做機關槍,機關槍火力猛射程遠,但這並不是說機關槍就是最好的,手槍步槍狙擊槍都是渣,而是各有各的用途。
這本來很好理解,然後,當你手裡有了一把機關槍,而你又狂熱的喜歡這把機關槍的時候,事情就變味了。你會說,機關槍一樣可以幹手槍的活,
- 我用機關槍比你用手槍還好使,
- 你覺得不好用,那是你不會用,
- 不信你看著……
這就走上邪路了。
機關槍這個例子,如果現實生活中真有這樣的人,你一定覺得他是瘋子。
但在IT圈裡,其實到處都是這種瘋子。隔三差五的各種語言撕逼、框架撕逼、陣營撕逼,本質上,不就這麼回事麼?
矯枉過正的說,“物件導向”,或者“物件導向粉”們,確實有走上邪路的傾向。
如果說你確實能把“機關槍”玩出“狙擊槍”的效果,那邪也邪得有個性,溜得飛起!問題是絕大多數人,沒有這種本事,邯鄲學步,就有些尷尬了。
我舉一個例子:
現在有兩個類,一個使用者類(User),一個部落格類(Blog),現在有一個釋出部落格的方法(Publish)。
那麼,“釋出部落格”這個方法,究竟是應該放在使用者的類裡面,還是部落格的類裡面?即:究竟是User.Publish(Blog)呢,還是Blog.Publish()?
以下為思考時間:
滴答……
滴答,滴答……
滴答,滴答,滴答……
如果按照“萬物皆物件”,“物件對映實體”,“方法就是物件的行為”……之類的格言來套的話,當然應該是User.Publish(Blog),你看,使用者 釋出 部落格,一一對應啊!美滴很~~就像我們老師教的那樣,名詞做物件,動詞做方法……
但有過一定開發經驗的同學,就知道應該是Blog.Publish(),但為什麼呢?這看起來好像不對啊?部落格怎麼會發布呢?部落格自己釋出自己?什麼鬼?不通啊!
確實不通,不過是你自己沒“通”;或者,一開始就錯了。
要理解這個問題,就得回到物件導向的“起點”,明白“物件導向”要解決的問題,不是什麼“對映客觀世界”,就這個問題,也還談不上什麼“繼承多型”(“封裝”勉勉強強,但根還不在這裡)。
讓我們再回頭複習遍:已經有了一堆一堆的方法,再引入一個又一個的“類”,目的是什麼?把方法裝進一個又一個的類裡面,分門別類,是不是為了照顧我們的“大腦”——這可憐的資源有限的人腦?電腦就沒這些麻煩,方法都不用,01010010000101001001……就OK了。所以,假設有50個類,是不是每個類裡的方法數目都差不多,勻稱一些,我們的分類就更有意義一些?
假設User.Publish(Blog)的邏輯成立的話,是不是還會有User.Publish(Comment),User.Agree(Blog),User.Logon(),……,User.FlyToSky()……一個系統,是不是幾乎所有的操作,都是User乾的?這User不是要上天啊!我們“分門別類”的工作,是不是就沒有意義了?以前是記一堆函式,現在是記User下面的一堆函式,有個毛用啊!
但我經常看到類似User這樣的萬能類,有輕重程度的差別,但本質上,這種程式碼,就是“披著‘物件導向’的皮”,幹著……幹著什麼事呢?幹著亂七八糟的事。
當然,還有濫用繼承,層層疊疊的像個十八層寶塔一樣,又百轉千回的像個死亡迷宮一樣,你咕噥一句“整複雜了”,架構師一臉傲嬌鼻孔朝天,“物件導向,高階貨!哪那麼容易的……”
碼字才真心不容易——這部落格從昨天寫到今天,差不多了。
做個總結吧:
- 物件導向,以及所有的軟體工程思想方法,其目的都是把複雜的問題簡單化,而不是相反。
- 所謂“簡單化”,指的是讓我們人類的大腦覺得“簡單”,而不是電腦。電腦?0101010010000010101010……才最簡單。
- 記住上面兩個原則,明白:軟體開發的目的是為了解決問題,而不是“炫技”。尤其是不要為了“炫技”而把本來就複雜的問題搞得更復雜……
(⊙x⊙;)
就醬紫,我要繼續愉快的擼程式碼去了,歡迎圍觀。