短小
- 20世紀(jì)80年代常說,函數(shù)不該長于一屏谷饿。
那時(shí)候一屏只有20行抢野,80列。
現(xiàn)在能顯示大概100行各墨,150個(gè)字符指孤,但是函數(shù)也不應(yīng)該占滿屏幕,20行封頂最佳贬堵。 - 代碼塊和縮進(jìn)
if語句恃轩、else語句、while語句等黎做,其中代碼塊應(yīng)該只有一行叉跛。該行大抵應(yīng)該是一個(gè)函數(shù)調(diào)用語句。
這也意味著函數(shù)不應(yīng)該大到足以容納嵌套結(jié)構(gòu)蒸殿。所以筷厘,函數(shù)的縮進(jìn)層級不該多于一層或兩層。
只做一件事
- 如果函數(shù)只是做了該函數(shù)名下同一抽象層上的步驟宏所,則函數(shù)還是只做了一件事酥艳。
- 要判斷函數(shù)是否不止做了一件事,還有一個(gè)方法爬骤,就是看是否能再拆出一個(gè)函數(shù)充石,該函數(shù)不僅只是單純地重新詮釋其實(shí)現(xiàn)。
- 只做一件事的函數(shù)無法被合理的切分為多個(gè)區(qū)段霞玄。
每個(gè)函數(shù)一個(gè)抽象層級
函數(shù)中混雜不同的抽象層級骤铃,往往讓人迷惑。一旦細(xì)節(jié)和基礎(chǔ)概念混雜坷剧,細(xì)節(jié)就會在函數(shù)中糾結(jié)起來惰爬。
要讓每個(gè)函數(shù)后面都跟著位于下一抽象層級的函數(shù)。
switch語句
問題:
- 太長惫企,當(dāng)出現(xiàn)新的條件時(shí)撕瞧,還會變得更長
- 不止做了一件事
- 違反了單一權(quán)責(zé)原則
- 違反了開閉原則,每當(dāng)添加新類型時(shí)雅任,就必須修改风范。
解決方案:
將switch語句埋到抽象工廠底下。
使用描述性的名稱
- 函數(shù)越短小沪么、功能越集中硼婿,就越便于取個(gè)好名字。
- 別害怕長名稱禽车。
- 別害怕花時(shí)間取名字寇漫。
- 選擇描述性的名稱能理清關(guān)于模塊的設(shè)計(jì)思路刊殉,并幫助改進(jìn)之。追索好名稱州胳,往往導(dǎo)致對代碼的改善重構(gòu)记焊。
- 命名方式要保持一致。
函數(shù)參數(shù)
最理想的參數(shù)數(shù)量是零栓撞,其次是一遍膜,再次是二,應(yīng)盡量避免三參數(shù)函數(shù)瓤湘。
- 參數(shù)不易對付瓢颅。
它帶有太多概念性。以StringBuffer為例弛说,作為參數(shù)傳遞時(shí)挽懦,讀者每次看到都得翻譯一遍。參數(shù)和函數(shù)名處于不同的抽象層級木人。 - 參數(shù)讓測試變的困難信柿。
如果參數(shù)多余兩個(gè),測試覆蓋所有可能的組合讓人生畏醒第。 - 輸出參數(shù)比輸入?yún)?shù)還要難以理解
信息通過參數(shù)輸入函數(shù)渔嚷,通過返回值從函數(shù)輸出。盡量不要讓信息通過參數(shù)輸出淘讥。
一元函數(shù)的普遍形式
向函數(shù)傳入單個(gè)參數(shù)有兩種極普遍的的理由圃伶。
你也許會問關(guān)于那個(gè)參數(shù)的問題。也可能是操作參數(shù)蒲列,將其轉(zhuǎn)換為其他什么東西,再輸出之搀罢。
還有一種不普遍但極有用的單參數(shù)函數(shù)形式蝗岖,事件。這種形式榔至,有輸入?yún)?shù)無輸出參數(shù)抵赢。小心使用這種形式。
盡量避免編寫不遵循這些形式的一元函數(shù)唧取。例如铅鲤,void includeSetupPageInto(StringBuffer pageText)。對于轉(zhuǎn)換枫弟,應(yīng)該使用返回值邢享,而不應(yīng)該使用輸出參數(shù)。StringBuffer transform(StringBuffer in)要比void transform(StringBuffer out)強(qiáng)淡诗,它遵循了轉(zhuǎn)換的形式骇塘。
標(biāo)識參數(shù)
向函數(shù)傳入布爾值是丑陋的做法伊履。它直接告訴我們這個(gè)函數(shù)不止做一件事,傳入true將會這樣做款违,傳入false則會那樣做唐瀑。
二元函數(shù)
盡管有些時(shí)候兩個(gè)參數(shù)剛好。比如Point p = new Point(0,0),笛卡爾點(diǎn)天生就有兩個(gè)參數(shù)螺捐。但是這是因?yàn)檫@兩個(gè)參數(shù)是單個(gè)值的有序組成部分赔蒲。
其他的就不好了,即使是如assertEquals(expected,actual)力穗,這樣的二元函數(shù)也有問題。你會經(jīng)常搞錯(cuò)這兩個(gè)參數(shù)的位置萍虽。這兩個(gè)參數(shù)沒用自然的順序睛廊。
盡量利用一些機(jī)制把二元函數(shù)轉(zhuǎn)換成一元函數(shù)。例如杉编,writeFiled(outputStream,name)超全,可以把writeField方法寫成outputStream的成員函數(shù),從而能這樣用:outputStream.writeField(name)邓馒∷恢欤或者,也可以把outputStream寫成當(dāng)前類的成員變量光酣,從而無需再傳遞它疏遏。還可以分離出類似FieldWriter的新類,在其構(gòu)造器中采用outputSteam救军,并且包含一個(gè)write方法财异。
三元函數(shù)
排序、琢磨唱遭、忽略的問題都會加倍體現(xiàn)戳寸。
當(dāng)然也有一些函數(shù)寫成三參數(shù)還是可以不錯(cuò)的。
參數(shù)對象
如果函數(shù)看來需要兩個(gè)拷泽、三個(gè)疫鹊、或三個(gè)以上參數(shù),就說明其中一些參數(shù)應(yīng)該封裝為類類司致。當(dāng)一組參數(shù)被共同傳遞拆吆,往往就是該有自己名稱的某個(gè)概念的一部分。
參數(shù)列表
有時(shí)脂矫,我們需要向函數(shù)傳入數(shù)量可變的參數(shù)枣耀。例如,String.format方法羹唠。
但是這個(gè)方法實(shí)則是二元函數(shù)奕枢。
動詞與關(guān)鍵字
給函數(shù)取個(gè)好名字娄昆,能很好的解釋函數(shù)的意圖,以及參數(shù)的順序和意圖缝彬。把參數(shù)的名稱編碼成函數(shù)名萌焰。例如write(name)和writeField(name),它告訴我們name是一個(gè)field谷浅,assertEqual()改成assertExpectedEqualsActual(expected,actual)會好些扒俯。這大大減輕了記憶參數(shù)順序的負(fù)擔(dān)。