本文為 一旬一題寫作計劃 中 重構(gòu) 專題內(nèi)文章,讀完本篇大約需要4分鐘。

合理正確的命名簡直是編程時最常頭疼的問題之一(僅次于寫文檔),我的強迫癥同事每次寫新需求的代碼時候都要為此糾結(jié)半天。 我們會使用像下面這種,大家提到最多的,類似“格式規(guī)范”的命名規(guī)范: Google java編程風(fēng)格指南中文版 Code Style for Contributors 這種規(guī)范規(guī)定了命名的格式,大大降低了代碼混亂度,但是對可讀性的貢獻卻還不夠。 好的代碼應(yīng)該表達出自己的功能,望文知義是我們的追求。
/*能讀,不好讀*/houzi.food(b) // the money eats a banana/*望文知義,與自然語言(右側(cè)的注釋)很接近*/monkey.eat(banana) // the money eats a banana我們開發(fā)中可能60%的時間都花在命名和閱讀代碼上了,如何讓代碼更“可讀”(更有語義),是個值得花時間琢磨的問題。這篇文章將會介紹些讓命名更具語義的實踐。
命名必須傳遞足夠的信息。 通常,對象代表一個事物概念,我們使用名詞來命名。用名詞的復(fù)數(shù)或加上 List 、 Map 后綴來命名集合。函數(shù)都是用來做事情的,函數(shù)的名字應(yīng)該由動詞開始。 于是我們建立了最基礎(chǔ)的規(guī)則:名詞命名對象,動詞命名函數(shù)。
我們編寫的大多數(shù)函數(shù)有個返回值,所以用動詞get開頭特別常見。對于簡單訪問對象屬性的方法,get還是蠻適合的,比如POJO和JavaBean的數(shù)據(jù)獲取方法。 但是多數(shù)情況下,get并不是一個好的選擇。想象有一個方法,它會連接到遠程服務(wù)器,搜索某個數(shù)據(jù)集,并將其排序后返回。我們可以把它叫做 getData,但這樣的命名就沒能提供足夠的信息,跟從本地獲取數(shù)據(jù)或者簡單訪問JavaBean沒有任何區(qū)別,讀者也無法猜測這個函數(shù)會做出些什么。如果換成fetchUserInfoAsync()之類的,函數(shù)的目的就一目了然了,讀者得到了函數(shù)做了更多的工作來提取數(shù)據(jù)的暗示。 我們可以提煉出一條新規(guī)則,即時直接訪問數(shù)據(jù)時用get,其他更復(fù)雜的情況應(yīng)當(dāng)另選更精確的動詞。比如做數(shù)學(xué)運算得出一個返回值的函數(shù),calculate 會比 get 合適。
試下給下面的函數(shù)選個動詞。
Item getItem(Item match) { for(Item temp : itemList){ if(temp.values == match.values){ return temp; } }}看看這個函數(shù)干了什么,不是簡單地獲取某個數(shù)據(jù),它在集合中搜索某個符合條件的元素并返回。searchItem或者findItem都是容易想到而且很不錯的選擇。試下描述函數(shù)的功能,從中摘取動詞,就是這么簡單。
有的人喜歡用do命名,仔細(xì)想想,每個函數(shù)都有do一些事情,do 幾乎不能提供任何有用信息。類似的詞語還有handle, perform, return。
Boolean返回值函數(shù)最適合用 is, are, was, were開頭,或者搭配情態(tài)動詞。
情態(tài)動詞(Modal verbs)本身有一定的詞義,表示語氣的單詞。但是不能獨立作謂語,只能和動詞原形一起構(gòu)成謂語。情態(tài)動詞用在行為動詞前,表示說話人對這一動作或狀態(tài)的看法或主觀設(shè)想。
也就是can, could, may, might, must, shall, should, will 和 would,這些詞隱含了假設(shè)當(dāng)前條件為真的反問信息。比如Button.isEnabled(),User.canaccess()。
Java語言中,方法是某個類里面定義的一個函數(shù),也就是方法跟類是有綁定關(guān)系、在類或者對象的上下文中運行。所以有時候函數(shù)名中沒必要再描述主語。比如一個保存信息的方法,可以叫做saveMessage();假如這是Message類的一個方法,就可以簡化為save()。你可以對比感受下Message.save()和Message.saveMessage()。
函數(shù)的簽名本身就告訴了讀者有什么參數(shù),再在方法名中描述就多余了。findUserByUserIdAndToken(String userId, String token) 可以簡化成 findUser(String userId, String token)。
雖然不是必要的,但如果遵循這種語義規(guī)范(況且也不難),能讓我們的代碼很清楚地表達出它的關(guān)鍵邏輯。重構(gòu)過代碼的同學(xué)應(yīng)該明白這種代碼的自描述性有多重要。
任何一個傻瓜都能寫出計算機可以理解的代碼,唯有寫出人類容易理解的代碼,才是優(yōu)秀的程序員。 ——《重構(gòu):改善既有代碼的設(shè)計》
錯誤代碼的影響力是有限的,bug很快會遁形;但能正確執(zhí)行的無法理解的混亂代碼卻會造成長遠的負(fù)面影響。多花一丟丟時間去提升代碼的清晰度,后面的開發(fā)才會更愉悅。
參考資料與擴展閱讀
Semantic method naming
編寫「可讀」代碼的實踐
Google Java編程風(fēng)格指南中文版
Code Style for Contributors
新聞熱點
疑難解答
圖片精選