VOOZH about

URL: https://read01.com/3G5345.html

⇱ 循序漸進地培養面向對象的思維方式 - 壹讀


Sunday, Apr 12, 2026

循序漸進地培養面向對象的思維方式

2014/08/11 來源:cnblogs

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

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

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

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

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

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

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

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

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

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

👁 Image
...

簡單解釋下業務場景:

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

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

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

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

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

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

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

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

一般來說,LoginServiceUserDao接口存在有其合理性。

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

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

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

2 Java平台中的面向對象舉例

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

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

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

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

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

3 面向對象不適用於所有業務場景

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新文章 / 服務條款 / 私隱保護 / DMCA / 聯絡我們

壹讀/READ01.COM