如今所有的Opening,只要有點(diǎn)底氣,都會要求candidate有OOD的能力、熟練運(yùn)用各種設(shè)計模式。然而在筆試及面試中,卻只能通過形如,“列舉GoF書中你知道的設(shè)計模式”,“畫出strategy模式的UML圖”之類的問題來進(jìn)行測試,在如今實(shí)習(xí)生都把GoF書翻爛的年代,這樣的問題如同,“請說出final, finally, finalize的區(qū)別”一樣,只能浪費(fèi)雙方的時間。綜觀面試經(jīng)驗(yàn),對于“闡述一下你對OOD的看法”的回答,無非兩類:“封裝、多態(tài)、繼承”或者“GoF的模式”,這樣的回答恰恰代表了候選人對OOD理解的層次。

在OOD這個domain里面,類比數(shù)學(xué)公理,我認(rèn)為Robert.C.Martin的OOD Principles已經(jīng)說的非常清楚,當(dāng)中最為核心的一條,就是SRP。所有其他的編程原則如同在五大Principles中的OCP、DIP更多的是基于SRP的一些推論,更不必說DRY原則等等一系列五花八門,變化多端的buzz word。我認(rèn)為所有的程序設(shè)計工作,其實(shí)最終的目標(biāo)都是為了達(dá)到隔離關(guān)注,將特定的需求交給專門的組件去完成。這里的組件在不同的上下文中含義不同,小至在單個系統(tǒng)模塊內(nèi)部,組件指的可能就是完成特定功能的Class/Function,大至SOA(另外一個buzz word)中,組件指的可能就是某個業(yè)務(wù)域服務(wù)系統(tǒng)。當(dāng)明確了SRP是終極目標(biāo)之后,OCP說的,只不過是“部分特定條件下的情況已經(jīng)被本組件解決完畢并隔離,如需要處理其他特殊邏輯,請通過擴(kuò)展的方式在特定的地方完成”;DIP則說“本實(shí)現(xiàn)所依賴的組件的具體實(shí)現(xiàn)選擇過程應(yīng)該由專門的選擇策略組件完成,本類的主要關(guān)注是利用這些依賴完成本類所標(biāo)稱需要解決的問題”;至于那個DRY原則,則更顯淺易懂了,本來就已經(jīng)有特定的組件把特定的關(guān)注解決掉了,還有必要重新解決一次么?
那么所謂的封裝、多態(tài)、繼承,甚至是GoF的各種模式,到底是什么呢?同樣的,類比數(shù)學(xué)中的概念,它們就是一些基于數(shù)學(xué)公理的推論,雖然我們可以通過公理一步一步的將所有的定理推論都推理出來,但極少數(shù)人會在實(shí)際運(yùn)用計算的時候這么做,因?yàn)樘恕M瑯拥模@些類似Best practice的東西的價值也僅僅在于,解決某一特定前提下的某一特定問題,這樣,你就明白為什么我深惡痛絕模式驅(qū)動編程:模式是為了解決特定問題而產(chǎn)生的,但這幫人的做法是為了運(yùn)用某種模式,而去創(chuàng)造該模式所符合的問題,這讓我想起那個關(guān)于數(shù)學(xué)家的笑話。然而我經(jīng)歷的團(tuán)隊(duì)中,這樣的情況屢屢發(fā)生,成為過度工程的頭號原因。
之前經(jīng)常有人問,如何鍛煉設(shè)計能力?我就會建議他們看一下那幾個principles,每天讀,讀通讀透,讓它們成為你的條件反射。在做設(shè)計和review設(shè)計的時候,不停的問自己,我一共有多少個問題?正在考慮的這個組件要解決什么問題?在它所處的粒度來看,它是否只有單一職責(zé)?等到每個問題的答案都是Yes的時候,我認(rèn)為這個設(shè)計至少不差。我之前看到過很多這樣的設(shè)計,大多數(shù)情況下,它們不會有一些fancy的設(shè)計模式名稱在里頭,但卻滲透著一股身經(jīng)百戰(zhàn)的老練,比如JQuery的core
同樣的,有一種顯而易見的bad smell:當(dāng)你的代碼庫中充斥著大量的設(shè)計模式名稱,而實(shí)現(xiàn)代碼卻看起來極其幼稚(我認(rèn)為至少得讀過Implementation Patterns或者Clean code),那么百分百的,你的團(tuán)隊(duì)中就至少有著一個急于想證明自己卻又適得其反的成員,該是時候找他談?wù)勊亩ㄎ缓统砷L計劃了。