循序漸進地培養物件導向的思維方式

來源:互聯網
上載者:User

標籤:Lucene   style   blog   http   java   os   io   資料   

 

  在我踏入軟體行業後,一直苦於沒有前輩指點。我常年困惑於兩個問題:一是怎樣培養物件導向設計的思維能力?二是怎樣進行架構設計,有無方法?

  因為我做了那麼多年項目,卻很少看到有漂亮的物件導向思維寫出來的代碼,覺得有必要提醒下年輕從業者。如今總結一下自己的經曆,希望對剛剛入行的朋友有些啟發吧。

 

我的基本觀念是,物件導向的思維方式是可以循序漸進地培養出來的。通俗地講,就是不斷地編碼實踐,量變會引起質變。

1 開發人員的思考動力不足

   記得參加工作後做的第一個項目是某電信局的運營支撐系統開發,採用的開發架構是Struts1+EJB+Hibernate的組合,WebLogic8作應用伺服器。

   彈指間,十年時光飛逝,慢慢適應了中年大叔的生活。

   有趣的是,經典的組合搭配至今沒有過時(千萬不要那麼快過時啊,靠它混飯吃啊),特別是在公司專屬應用程式中,例如大家常說SSH組合:Struts/SpringMVC + Spring/EJB + Hibernate/Mybatis/JPA等。

    開源架構的出現,使得只要在其基礎上進行二次開發就可以大大降低開發工作量。只要進階工程師搭建好了項目的開發工程,初級開發人員就可以依照模版代碼,依葫蘆畫瓢,流水線作業進行業務功能開發。

從項目組整體的生產效率角度看,這確實是很大的進步。各個成員不同分工,各自做好自己的一部分工作即可,也符合現代企業管理的理念。但從個體的角度看,也客觀造成了一些弊端,對初級開發人員,他就是流水線長的一個螺絲工,沒有機會去思考如何進行物件導向的設計。

   這裡我以一個常用的使用者登入模組舉例,系統採用經典的三層架構進行分層,類圖如下:

  

 

簡單解釋下業務情境:

1) 使用者用瀏覽器訪問系統登入頁面,輸入使用者名稱與密碼,提交表單。

2) 系統對使用者的使用者名稱和密碼進行驗證,並對使用者的訪問進行日誌記錄以便以後作審計。其中資料庫中儲存的使用者密碼資訊是加密後的字串。

 

作為一個初級開發人員,開發業務功能常常只需要複製粘貼圖中的6個類即可。有時甚至連PasswordEncoder類都省去。還有些項目組有開發自己的代碼產生工具,甚至連複製粘貼工作都省去,只需要對工具產生的程式碼作少量修改即完成了開發。

 

回到類圖,這裡的LoginService和UserDao介面是否有必要定義?複製粘貼以及代碼產生工具使得工作量成本很低,初級開發人員就沒有動力去思考這個問題的,依葫蘆畫瓢完成功能,打完收工即可。

 

我個人的觀念是有沒有必要取決於具體的項目需求與人員分工。

1) 如果該業務模組由1個開發人員完成,系統不需要支援多資料庫,也就是UserDao沒有多個實作類別的需求,則UserDao介面可以移除掉。同時如果系統只有通過資料庫查詢認證的可能,LoginService也沒有多個實作類別的需求,則也可以移除掉。

2) 如果項目組中該模組每一層都由不同的人員分工合作,則由於層次間依賴的需要,引入介面使得上一層可以更早地開始開發,也使得上一層的單元測試變得簡單。在這種情況下,LoginService和UserDao介面有存在的合理性。

3) 在項目中,某些模組因為業務需要Service層和Dao層必須要有多種實作類別。從代碼風格一致性角度考慮,存在一個類對應一個介面的情況也是可以容忍的。這樣是為了維護代碼的可讀性,也客觀上預留了系統的可擴充性。

一般來說,LoginService和UserDao介面存在有其合理性。

 

    這些開發架構對通用功能進行了大量的封裝,其本身源碼中包含了大量OOD的思想。提供給開發人員進行二次開發時,單表單的增刪改查由於業務需求簡單,就體現不出OOD的價值了。這在一定程度上,使得開發人員去思考OOD的動力不足。

   比如MVC架構中對於控制器與視圖的分離,業務模型類與Servlet API的轉換這些恰恰是複雜的需要OOD抽象能力的,架構已經給你實現了。架構做的多一點,所以開發人員就輕鬆一點。再比如Spring中對於Java bean的建立與管理,依賴關係的注入,基於攔截器和動態代理機制來實現的聲明式事物以及Tlog,還有與其它架構的整合支援等複雜點,它都給你實現了。還有Hibernate中實體物件與關係型資料庫中表的對應轉換,對API調用翻譯轉換成SQL語句,對多種資料庫文法的支援,查詢結果的緩衝等,也是複雜點。

    反過來說,如果你不用任何架構,去實現一個中等規模的Web應用。看看自己寫的代碼與現在基於架構二次開發的代碼差別大不大,差別在哪裡。我想,自己去實現未必會比開源大牛們設計的更好,但卻完全可以體會到複雜點痛點在哪裡,OOD是不是有應用情境,因為寫的過程中蛋疼了。編程雖易,OO不易,且編且珍惜。

2 Java平台中的物件導向舉例

   Java語言的API規範中,可以說是處處體現了OOD。這裡僅僅舉Servlet和JDBC規範兩個例子,不同的廠商底層對Servlet  API的實現,JDBC驅動的實現,完全對開發人員屏蔽,兩套規範都實現了精鍊的抽象。

Servlet  API把HTTP協議中的請求資訊封裝成HttpServletRequest對象,響應訊息封裝成HttpServletResponse對象。開發人員直接從這兩個對象中擷取HTTP通訊中的各種HTTP頭資訊,參數資訊,以及完成對HTTP用戶端的響應資訊輸出。

JDBC API使得開發人員可以不考慮具體的資料庫類型,用相同的API完成與資料庫的互動。

    完全可以說,掌握了Servlet API就掌握了Java Web應用開發;掌握了JDBC API就掌握了與Java資料庫應用開發。

    Java開源社區奉獻了大量優秀的架構,例如:Lucene,Hadoop,Hbase,Mina,Netty,ActiveMQ等在互連網和電商行業得到廣泛應用。(看來搞Java一時半會不會找不到工作,不過少年你天資聰穎活力青春,我還是建議你搞IOS開發簡單粗暴,不解釋)。

3 物件導向不適用於所有業務情境

    在Java語言中,一切都是對象。那是不是所有的業務問題,都可以用物件導向的方式去設計實現呢?要知道“尺有所短,寸有所長”,OOD也不是全知全能的宇宙真理啊!

    舉個例子,比如要實現一個自然整數n的階乘。你再怎麼物件導向去思維,也無法去抽象出物件模型對應這個問題。這種情境下,反而過程式的實現更加簡單直接。還有很多數學推導公式的求解也是如此。

   再舉個例子,項目中有個實現最短路徑演算法的需要。雖然我用物件導向思維方式活生生寫了10來個類實現了功能。網上一搜,C語言用鄰接矩陣儲存的方式來實現的一兩個類就實現了該功能。物件導向的方式可能更加適合開發人員去讀懂,對於電腦來說,可能面向過程的實現運行效率更高。

    在我看來,電腦技術的本質是計算。各種二進位表示的資料,通過網路通訊進行傳輸,然後系統對計算的結果進行儲存或通過網路返回給調用方。

    我們的思維方式中不能排斥,不包容其它的設計理念。認為OOD一招打遍天下,就有點愚蠢了。這點其實挺難的,我們從小的受到的教育是同一種觀念,同一種政治正確性,甚至同一種價值觀,不允許有異見。經常能看到論壇上非此即彼的對罵。好在互連網的開放性,使得越來越多的人有了多元的世界觀,價值觀。

 

4 學習設計模式可協助理解OOD

設計模式列舉了一些經典業務情境的最佳實務,非常值得借鑒學習。我們學習設計模式中常用的23種招式,最終目的是培養自己對OOD的悟性。

就好像我們看武俠小說裡面,十八般武藝招數全部學會,還不抵九陽神功一掌。對內功深厚的大師來說,飛沙走石一花一葉都可傷人性命。

但學武之初,紮紮馬步,練練兵器拳法,還是有助於培養悟性的。

同時又不能生搬硬套為了模式而模式,覺得它精妙就想時時處處都模式了。舉個邪惡點的例子,由於教育的缺失,就如在學生時代男生普遍性啟蒙都是靠觀摩島國愛情動作片來領悟啪啪啪的要義一樣,你要是模仿男主角把裡面的每個情境每個招式都實踐一遍吧,有些高難度動作會完成不了還會傷害自己,你懂的。

設計模式的精髓就在遵循開閉原則,將通用代碼向父類抽取,對可變的行為抽象成介面進行封裝。模式的提煉應該是水到渠成的事情。

只要平時養成面向介面編程,依賴於抽象而不是依賴於具體實作類別的開發習慣。當編碼實踐經驗達到一定的臨界點後,量變引起質變,不知不覺中發現寫的代碼已經是運用了設計模式在裡面了。大家都聽說過,一萬小時理論,精通一項技能往往需要持續實踐一萬小時以上。但凡5年以上紮實地編程實踐,即使得不到高人指點,也會對OOD頓悟。

5 持續重構可協助對抽象思維的培養

   OOD的精華在於抽象,抽象,再抽象。但是每個人對於設計經驗有一個積累的過程,不可能一開始就設計的非常完美,能應付項目中所有的需求。

    抽象思維能力,更需要一個循序漸進的培養過程。我們不斷地學習優秀開源架構的源碼,學習設計模式都是一種外部手段,旨在迫使自己大腦中學會抽象思考的方式。

    所面臨的問題域是一個子系統,一個模組,那抽象的思維培養的是物件導向設計的能力,系統分析與領域建模的能力。放大了看,如果面臨的問題域是整個系統或者多個系統,則培養的就是系統架構設計的能力。

有過一定編程實踐經驗的人都有過這樣的經曆,系統中如果有重複的程式碼片段出現2~3次就會覺得很噁心,尤其是一大段大段上百行幾乎一樣的代碼。因為每個人的編碼能力經驗不同,開發的時候很可能設計不到位。那可不可以將其進行提煉複用呢?

答案是可以,因為我們有重構(Refactor)這個法寶。

    持續的重構是可以有效改進物件導向的設計的。我常常在看別人的代碼時候,不自覺地幫著進行重構,這隻是一種習慣。當然,必須在尊重原作者的前提下,一步步小範圍內重構。

落實到細節上,痛點在於類和方法的命名,類的職責劃分,抽象的粒度大小適中。這些真的只能靠經驗積累,去領悟理解了,沒有一定的標準,什麼是好,什麼是不好。我覺得起碼命名要清晰,易於理解,類的職責要專一,方法長度不能過長。細節方面可參照大牛Martin寫的那本關於重構的聖經書。

 

   最後,一個人對知識的理解,不是線性增長或者拋物線上升的,應該是階梯形上升的。每上一個台階,需要熬過一段不規則的積累沉澱期,再由外界因素的觸發引起內在的覺醒才能繼續到下一個台階。以前死活不明白的事情,或許隨著年齡增長,都釋然了。聞道有先後,但終究會頓悟。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.