個人學習雜談&java抽象雜談

在時隔一年多重新開始寫博客後,我翻閱了一下以往寫的博客,發現了一個非常神奇的事情——我的博客可讀性真的不強!這興許是因爲我在寫博客的時候並不花太大的力氣去組織語言,通篇寫的有點流水賬;但另一方面,或許是我在寫博客的時候,總是隻把我自身最新的理解給寫下來,並不考慮讀者的知識基礎是否恰好可以讀懂。由於我的博客是以源碼閱讀、設計模式等內容爲主的,所以這篇文章簡單談一談我在java的設計、抽象等方面的一點體會。

最近我在很多場合下,與有許多人在學習方式、架構思想等方面有過一些討論,由此回顧在開發上的整個學習歷程,也有一些淺顯的感悟,在此一併說了。

特別提示,這是一篇總結型而非技術型的博客,如果是着急獲取知識的讀者,就不要繼續閱讀以免浪費自己的時間了!

在這個信息化的社會,學習的方式可謂是多種多樣,各類博客、教程、視頻以及開源代碼成爲了不少碼農們學習的核心手段,書本學習在一定程度上已經漸漸暗淡,雖然大部分程序員也會閱讀一定量的書籍,以求知識體系的健全,但是在書本的選擇上,越來越多的人趨向於生動易懂的書本,而放棄一些較爲經典的書籍。

這顯露出一個非常嚴峻的事實,大家在學習中,夾雜着一種急於求成的浮躁,因此總是選擇能夠快速攝取知識的學習方式,但是這裏我不得不提出一個問題——學習,究竟是爲什麼而學習的?知識?還是能力?

大學的時候,我曾經在和一個學弟的談話中聽到了這麼一句話“我們學習不就是爲了獲取知識嘛,至於怎麼獲取的這個知識,真的重要嘛?”,這位學弟有一些自己的體會,我尊重他的想法,但是在這裏我想說的是,我個人並不認爲學習是在單純地獲取知識,假若只是獲取知識,我們爲什麼還要在大學期間,在別人都在喫雞lol的時候認真學習呢?只需要花幾個月時間報個培訓班也同樣可以獲取知識呀?

在有的時候,學習或許確實是爲了獲取知識,比如當你有個問題需要快速做修改的時候;但是在更多的時候,學習應該是以個人能力的培養爲目的的,“自己已經不再是以前的自己了,知識只是副產品罷了!”

吾生也有涯,而知也無涯,以有涯隨無涯,殆矣!

莊子這話八面玲瓏,對不同的人與事亦是吹萬不同,但是這話放在知識日新月異的IT界,卻是一點都不唐突。我相信在這世上沒有哪個程序員可以說“IT方面所有知識,我都懂!”,大家在遇到棘手的問題時候,依舊需要依賴於互聯網查找解決方案,如果只從知識的層面來看待問題的話,程序員之間豈非絲毫沒有任何差別了?反正百度誰都會用嘛!然而對問題的一種潛意識的感覺,對尋找解決方案的一種敏銳的嗅覺,卻不是知識量所能解釋的了的。

當然,我並非說知識或者知識量不重要,相反個人知識量是非常重要的。知識可以成爲能力的一部分或者成爲提高能力的一個可靠途徑。但是,至少我認爲,不能把知識當做能力的全部。

相信不少人在初學階段遇到一些比較坑的問題的時候會覺得十分鬱悶甚至暴跳如雷,這是人之常情,因爲無論怎樣,這個看似並不能對你的知識量起到多大幫助的問題佔用了你大量的時間。“如果你在學習中連解決不了的問題都遇不到,你的能力如何提高呢?”,這是我IT技術的授業恩師曾經說過的話,我對此記憶猶新(大體意思是這樣,語言組織可能並不完全相同),同樣也是由於他在學生學習方式上的一些執着,讓我一度對學習方式上有較多的思考。我不認爲我是個能力出衆的人,在知識量上也完全是個初學者的水平,但是我相信在學習方式上做的思考,我應該超過了半數的程序員。

誠然,博客、教程可以幫助人們快速獲取知識,下載例程閱讀可以幫助人們快速上手,生動的書籍可以幫助人們快速地理解一些晦澀難懂的知識,這些學習方式在當今快節奏的工作狀態下是不可或缺的手段,但是這並不能成爲學習的全部,當自己通過各種快速學習的手段獲取的碎片化的知識達到一定程度的時候,靜下心來,仔細閱讀一本值得推敲的經典的書籍,或許會得到一些不一樣的體會,而這些體會,與你經歷產生的作用,纔是你自己的知識寶庫。即便這本書十分晦澀難懂,但“經讀百遍,其義自見”,將一本好書成爲長期的學習參考,當徹底將這本書嚼爛的時候,無論你的知識量、對於該領域的深刻體會、或是自身的能力,都會得到極大的提高。

而《設計模式》一書可謂是一個非常好的例子了,在我前面寫的博客中,大概有那麼兩三篇水水地提過具體的設計模式,但是說的較爲淺顯,很多時候也就是照抄書上的例子,或是給出自己碰到的一些典型的可以說明某種模式的案例,但是從未去系統整理過設計模式,一方面,這是由於個人能力尚有欠缺;另一方面,也是設計模式本身有他知識性質的獨到之處。

設計本身就是一個非常主觀的事情,你可以說一個好的設計比一個不好的設計要好得多,但是你很難判斷兩個同樣不錯的設計誰更好。千古文人相輕,而設計也和文學類似,一個設計的好壞,需要取決於此情此景下是否能改善遇到的問題,這還不盡然,即使完全相同背景下兩個不同的設計,也很難衡量好壞。常有程序員覺得他人的設計十分糟糕,卻未曾仔細體會過他人設計的初衷。一個好的架構設計師應該有對他人設計的足夠的包容心,在仔細體會他人設計緣由後再提出自身的意見;同樣一個好的架構設計師也應該能包容他人對自己設計的不尊重。這並非是單純地學術理論,而是軟件設計的事實,這世上沒有最好的設計,舉個極端例子:幾乎所有的軟工著作都提倡過程調用,因爲這可以讓功能更加模塊化,但是如果你仔細讀一本涉及系統底層知識的書籍就會發現,這些書提出了幾乎完全相反的建議,因爲過程調用會增加系統性能的開銷。不同設計的利弊原本就是需要開發人員自己去權衡的,並沒有標準的答案。

如果將寫代碼比作行軍打仗,那麼設計就是兵法,《設計模式》就是一部兵書。你可以通過熟讀兵書來通曉兵法,也可以通過一些對這本兵書的解讀(G4發佈《設計模式》後其他人所著各類設計模式的書籍)來更加直觀易懂地瞭解兵法,但是沒有實戰經驗,一切的精通都是紙上談兵。相反,如果你擁有相當量的實戰經驗,此時靜下心來細讀一部兵書,一種感同身受的體會就會油然而生,此時若能受到某一事某一言的刺激,愈來愈多的體會直至融會貫通,未來設計豈非得心應手?我曾經在給低年級研究生面試時候提問“什麼叫做面向對象?”,結果發現回答不是支支吾吾就是極爲官方(封裝、繼承、多態云云),雖然官方回答並不算錯,但是我認爲能說出自己體會的纔是真正瞭解面向對象的人,真若融會貫通的,自己給出兩句定義又如何?“大海中泛出一點浪花罷了”。

但即使當真達到如此也不要過分狂傲自驕,如我前文所說,設計本身就是個利弊權衡的事情,如同戰場上沒有哪種陣勢是真正所向無敵的。戰場上排兵佈陣的最終方案由主帥決定,屬下即使有更爲優秀的方案(大多數是自認爲優秀),也只得建議,而不能違抗命令,自亂陣腳者必敗。設計上亦是如此,即使你擁有很強的設計能力,也必須遵循項目整體的設計規範,除非你是系統的首席架構,並且系統正處於重構階段,否則胡亂違背系統整體規範而使用自己的設計理念,只會讓代碼變得更加晦澀難懂。

說到規範,不知大家是否想過,爲何java能作爲一種承載大體量工程核心架構的語言?論效率不如c、c++,論方便不如js、php,雖然有着類庫衆多的優勢,但是與近幾年的語言黑馬python相比倒也有些暗淡,何況類庫衆多本身不也是由於語言本身存在某種優勢,纔會有衆多的開發人員投入智慧與經歷,生成各種開源第三方的框架與類庫嘛?

規範,依然是規範,我認爲java最大的優勢就是其幾乎滲透到各個角落的規範。事實上在我接觸到的所有語言中,java的語法應該算是最爲規範的了:變量必須定義類型(這裏不考慮泛型)、參數必須寫明(這裏不考慮可變參數的寫法)、代碼必須以類的結構去定義。。。。諸多的規範,外加java本身將報錯分發給編譯(Error)和運行(Exception)以及JVM對垃圾處理的一些機制,造就java本身容錯性上的強大。在一個大型項目開發過程中,多名程序員之間的協調必須以規範作爲約束,而如果語言本身就有很強的規範,那他自然就天生具有承載大體量項目的優勢了。

說到java的規範,又不得不提一下一個名爲接口的東西。對於一個java開發人員來說,接口應該是一個熟悉的不能再熟悉的名詞了。接口這個概念究竟是誰最先提出的,我不清楚,但是接口這個詞彙被用的最多的,至少再軟件開發的世界中,當屬java程序了。其實初學java的時候我覺得很奇怪,爲啥接口要叫接口呢?按類族來觀察,接口應該是最上面,作爲類族老祖宗的存在,爲啥取了個好像在最外面的名詞——接口,呢?

爲什麼華碩的電腦可以連接戴爾的顯示器?因爲他們都有VGA、HDMI接口。接口,這個名詞本身象徵着規範,接口的兩端都遵循這個規範,因此即使毫不相干的開發者開發出的東西也能輕而易舉的結合。而對於java中的接口而言,接口的兩端,自然就是接口的實現和接口的調用了。調用者和實現者往往由不同的人去開發,而大家都遵循接口中原本做好的定義,因此,不同的開發人員的代碼纔可以簡簡單單的互相調用,而這個接口的定義者,或是公司內部的架構師,或是IT社區最具權威的公司或機構,因此纔有了“一流公司寫接口,二流公司寫實現。”這樣的話。

規範興許是件好事,但是在某些時候卻是一件不怎麼方便的事情,因爲這可能會造成不可避免的代碼重複。因此,纔有了java中一些動態化的語法:泛型、反射、註解。而這三者中,最具核心地位的,自然就是幾乎所有框架都會用到的反射機制了。

剛剛說過了,接口分離了調用和實現,而如果讓我用一句話概括反射就是:動態調用+動態實現。java中,調用包含了初始化、執行方法、獲取內部變量等等,而當你無法準確寫下調用的具體內容的時候,當你需要通過一些字符串等等的標記去讓代碼動態調用的時候,反射自然是首當其衝的選擇(具體用法不提了);而當你的接口的實現並不確定的時候,java的動態代理(也在java.lang.reflect包下)則是最好的選擇(mybatis、spring的AOP、dubbo等等都是如此實現的)。而泛型則主要抽象了變量類型的定義,其主要目的是避免了強制轉換。至於註解,則是作爲一種標記的方式,在反射過程中作爲一種判斷條件。

至此,我對於java的接口、動態、抽象的主要理解就基本說完了,學識有限,如果讀者有不同的意見也歡迎探討。接下來的細節都是對這些概念的具體實現和應用,不在本文範疇內。而反射也恰好可以成爲設計的利弊權衡理念的一個重要標準。反射動態了抽象了實現,但是拋棄了規範,讓原本在編譯過程中就可以拋出的error變成了只有在運行過程中才會產生的exception。這種利弊兩面性,則對於程序員在使用反射時候權衡的一個更高的要求。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章