《隨筆一》—— “ 【代碼整潔之道 Clean Code】 提煉總結 一 ”

目錄

第一章《整潔代碼 》

第二章《 有意義的命名》

第三章 函數

短小

只做一件事

命名合適且具有描述性

函數參數儘量少

標識參數

參數對象

接受可變參數的函數


本人代下CSDN資源,付費下載。不同積分的資源,付費的金額不同:

10積分之內的,每個書籍資源1.5元。
10→20積分之內的,每個資源2元。
20→30積分之內的,每個資源2.5元。
30→40積分之內的,每個資源3元。
40積分以上的,每個資源3.5元。
下載的資源可以是你發過來的CSDN下載的鏈接,也可以發資源的詳情信息,然後我給你找,都可以。

像一般的CSDN的資源都是 10 或者 20 積分之內的,如果你不是經常下CSDN,特意去買一個會員,實在是太虧了(一個最低都要98元一個月,然後一個月之內只能下載30個資源)。有意者可以加扣扣:2572722931(微信同樣)。我來幫你下載。童叟無欺,舉報的人都生兒子沒P眼的人。啪啪啪的時候猝死。


第一章《整潔代碼 》


  這章先是給我們傳遞一個觀點:整潔代碼是十分有必要的。然後就列舉了幾位java大師級人物對整潔代碼的定義和看法。

    真正有用的就是這些大師人物的觀點,都是經過幾十年的編程經驗總結而成的,下面我再將這些觀點進行總結,得到以下幾個“真理”:

 

  •   儘量減少依賴關係,便於維護
  •   簡單直接,充滿了乾淨利落的抽象和直截了當的控制語句。
  •  能夠全部運行通過,並配有單元測試和驗收測試
  •  沒有重複的代碼(提取公共方法和公共類)
  • 寫的代碼能夠完全提現我們的設計理念(類、方法、屬性的命名)

 


第二章《 有意義的命名》


●    在給 標識符 命名的時候應該選擇能夠體現本意的名稱,最好能體現該名稱是幹嘛的,有什麼作用,做什麼事情,如何使用等等。 這樣可以讓人更容易理解和修改代碼。注意:  在閱讀或修改過程中,如果發現有更好的名稱, 就要換掉舊的。

舉個栗子:以下的這句代碼裏的d就不算是個好命名。名稱d 什麼都沒說,它沒引起我們對時間消逝的感覺,更別說單位是天了:

int d; // elapsed time in days || 經過了幾天時間

我們應該選擇這樣的指明瞭計量對象和計量單位的名稱:

int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;

●  我們應該避免留下隱藏代碼本意的錯誤線索,也應該避免使用與本意相悖的詞。例如,別用accountList來指一組賬號,除非它真的是List類型,用accountGroup、bunchOfAccounts,或者直接用accounts,都是更好的選擇。

儘量提防長得太像的名稱。想區分XYZControllerForEfficientHandlingOfStrings和XYZControllerForEfficientStorageOfStrings,會花費我們太多的時間。因爲這兩個詞,實在太相似了。
 

注意:  不要用 小寫字母 “ l ” 和 " O"  做變量名,特別是組合使用的時候。

 


 

● 儘量避免使用數字系列命名(a1、a2…….aN)。這樣的名稱純屬誤導,因爲很多時候完全沒有提供正確的信息,沒有提供導向作者意圖的線索。

廢話是另一種沒有意義的區分。如果我們有一個Product類,還有一個ProductInfo或ProductData類,那麼他們的名稱雖然不同,但意思卻無區別。這裏的Info、Data就像a、an和the一樣,是意義含混的廢話。


注意,只要體現出有意義的區分,使用a、the這樣的前綴就沒錯。例如,將a用在域內變量,把the用於函數參數。

 


● 我們要使用讀得出來的名稱。如果名稱讀不出來,討論的時候就會不方便且很尷尬,甚至讓旁人覺得很蠢。

例如,變量名稱是beeceearrthreecee,討論的時候讀起來簡直像沒吃藥。

 


 

單字母和數字常量有個問題,就是很難再一大篇文字中找出來。

找MAX_CLASSED_PER_STUDENT很容易,但想找數字7,就很麻煩。

同樣,字母e也不是個便於搜索的好變量名。因爲作爲英文中最常用的字母,在每個程序、每段代碼中都有可能出現。

單字母的名稱可以用在很小的函數中作爲局部變量。 名稱長短應與其作用域大小相對應,若變量或常量可能在代碼中多處使用,應賦予其以便於搜索的名稱。
 

下面舉個例子:

for (int j=0; j<34; j++)
 {
s += (t[j]*4)/5;
}

VS

int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;

for (int j=0; j < NUMBER_OF_TASKS; j++) 
{
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}

按整潔代碼的要求來評判,第一段代碼會讓讀者不知所云,第二段代碼比第一段好太多。第二段代碼中,sum並非特別有用的名稱,但至少他搜索得到。採用能表達意圖的名稱,貌似拉長了函數代碼,但要想想看,WORK_DAYS_PER_WEEK要比數字5好找得多,而列表中也只剩下了體現我們意圖的名稱。
 


避免思維映射


我們取名的時候要避免思維映射,不應當讓讀者在腦中把你的名稱翻譯爲他們熟知的名稱,也就是說取名不要繞彎子,而是要直白,直截了當。

 在多數情況下,單字母不是個好的命名選擇,除非是在作用域小、沒有名稱衝突的地方,比如循環。循環計數器自然有可能被命名爲i,j或k(最好別用字母l),這是因爲傳統上我們慣用單字母名稱做循環計數器。
 


類名儘量用名詞


類名儘量用名詞或名詞短語,比如Customer, WikiPage,Account, 或 AddressParser。

類名最好不要是動詞。

 


方法名儘量用動詞或動詞短語。比如postPayment, deletePage, 或者save。

屬性訪問器、修改器 (mutator )和 斷言應該根據其value來命名,並根據標準加上get、set和is前綴。

舉個栗子,這裏的getName、setName等命名都是可以的:

string name = employee.getName();
customer.setName("mike");
if (paycheck.isPosted())...

 


 

我們需要爲一個抽象概念挑選一個詞,並堅持下去。

例如,使用fetch、retrieve和get來給在多個類中的同種方法命名,你怎麼記得住哪個類中是哪個方法呢?

 

不要把函數中的參數名的名稱跟某一個函數聲明的名稱一樣。  函數名應該是獨一無二的,而且還要保持一致。

 

同樣,在同一堆代碼中混用controller、manager,driver,就會令人困惑。DeviceManager和Protocol-Controller之間有何根本區別?爲什麼不全用controller或者manager?他們都是Driver嗎?這就會讓讀者以爲這兩個對象是不同的類型,也分屬不同的類。

所以,對於那些會用到你代碼的程序員,一以貫之的命名法簡直就是天降福音。
 


記住,只有程序員纔會讀你寫的代碼。所以,儘管去用那些計算機科學領域的專業術語、算法名、模式名、數學術語。

對於熟悉訪問者(Visitor)模式的程序來說,名稱AccountVisitor富有意義。給技術性的事物取個恰如其分的技術性名稱,通常就是最靠譜的做法。
 

如果不能用程序員熟悉的術語來給手頭的工作命名, 就採用從所涉問題領域而來的名稱吧。

 


 

很少有名稱是可以自我說明的。所以,我們需要用有良好命名的類,函數或名稱空間來放置名稱,給讀者提供語境。若沒能提供放置的地方,還可以給名稱添加前綴。

例如: 假如我們有名爲firstName、lastName、street、houseNumber、city、state和zipcode的變量。當他們擱一塊兒的時候,的確是構成了一個地址。不過,假如只是在某個方法中看到一個孤零零的state呢?我們會推斷這個變量是地址的一部分嗎?

我們可以添加前綴addrFirstName、addrLastName、addrState等,以此提供語境。至少,讀者可以知道這些變量是某個更大變量的一部分。當然,更好的方案是創建名爲Address的類。這樣,即便是編譯器也會知道這些變量是隸屬於某個更大的概念了。

 

另外,只要短名稱足夠好,對含義的表達足夠清除,就要比長名稱更合適。添加有意義的語境甚好,別給名稱添加不必要的語境。
 


最後總結


其實,取一個好名字最難的地方在於需要良好的描述技巧和共有的文化背景。與其說這是一種技術、商業或管理問題,還不如說這是一種教學問題。

不妨試試上面列出的這十二條規則與要點,看看你的代碼可讀性是否有所提升。而如果你是在維護別人的代碼,或者是在重構,效果應該會是立竿見影的。

 


本文涉及知識點提煉整理


 

  • 要點一:要名副其實。一個好的變量、函數或類的名稱應該已經答覆了所有的大問題。一個好名稱可以大概告訴你這個名稱所代表的內容,爲什麼會存在,做了什麼事情,應該如何用等。
  • 要點二:要避免誤導。我們應該避免留下隱藏代碼本意的錯誤線索,也應該避免使用與本意相悖的詞。
  • 要點三:儘量做有意義的區分。儘量避免使用數字系列命名(a1、a2…….aN)和沒有意義的區分。
  • 要點四:儘量使用讀得出來的名稱。如名稱讀不出來,討論的時候會不方便且很尷尬。
  • 要點五:儘量使用可搜索的名稱。名稱長短應與其作用域大小相對應,若變量或常量可能在代碼中多處使用,應賦予其以便於搜索的名稱。
  • 要點六:取名不要繞彎子。取名要直白,要直截了當,明確就是王道。
  • 要點七:類名儘量用名詞。類名儘量用名詞或名詞短語,最好不要是動詞。
  • 要點八:方法名儘量用動詞。方法名儘量用動詞或動詞短語。
  • 要點九:每個概念對應一詞,並一以貫之。對於那些會用到你代碼的程序員,一以貫之的命名法簡直就是天降福音。
  • 要點十:通俗易懂。應盡力寫出易於理解的變量名,要把代碼寫得讓別人能一目瞭然,而不必讓人去非常費力地去揣摩其含義。
  • 要點十一:盡情使用解決方案領域專業術語。儘管去用那些計算機科學領域的專業術語、算法名、模式名、數學術語。
  • 要點十二:要添加有意義的語境。需要用有良好命名的類,函數或名稱空間來放置名稱,給讀者提供語境。若沒能提供放置的地方,還可以給名稱添加前綴。

 


第三章 函數



短小

 

《代碼整潔之道》作者Bob大叔寫道 “ 函數的第一規則是要短小。第二規則還是要更短小。 ” 一般20行封頂最佳。

還建議我們函數不應該大到足以容納嵌套結構。所以, 函數的縮進層級不該多於一層或兩層。這樣就好的閱讀與理解。

 


只做一件事

 

函數應該只做一件事情。只做一件事,做好這件事。

有哪些方法可以判斷該函數只是做了一件事:

  • 如果該函數只是做了該函數名下同一抽象層上的步驟, 則該函數還是隻做了一件事。
  • 要判斷函數是否不止做了一件事, 還有一個方法,,如果你可以從該函數中提取另外一個函數,該函數不僅只是單純地重新詮釋其實現[G34]。

命名合適且具有描述性

 

“如果每個例程都讓你感到深合己意,那就是整潔的代碼。”要遵循這一原則,大半工作都在於爲只做一件事的小函數取個好名字。函數越短小,功能越集中,就越容易選擇描述性名稱。

 

我們爲函數取個描述性的名稱,不要害怕取了長名稱。長而具有描述性的名稱,比短而令人費解的名稱好。而且長而具有描述性的名稱,比描述性的長註釋要好。而且選擇描述性的名稱能理清你關於模塊的設計思路,以後好並幫你改進之,而且一個名字是否好尋找可以對代碼進行有利的重構。

不要害怕花時間選擇一個名字,可以嘗試使用幾個不同的名稱,並閱讀每個名稱對應的代碼。然後使用IDE嘗試使用不同的名稱,直到找到一個儘可能具有描述性的名稱。

 

還要記住的是:給函數 命名方式要一致,並且堅持下去。

 


函數參數儘量少

 

最理想的函數參數個數是零參數,其次是單參數,再次是雙參數,應儘量避免三參數及以上參數的函數,有足夠的理由才能用三個以上參數(多參數函數)。

 

輸出參數比輸入參數更難理解。當我們讀取一個函數時,我們習慣於通過參數將信息輸入到函數中,然後通過返回值將信息輸出。我們不太期望信息通過參數輸出。

當我們編寫二元參數的時候,看看能不能利用某些方法將其轉換成一元函數


標識參數

 

儘量避免將布爾值傳遞給一個函數, 因爲這樣相當於告訴我們這個函數不止做一件事,如果傳遞true ,它做這一件事; 如果傳遞false ,它做另一件事。

 


參數對象

 

當一個函數似乎需要兩個或 三個、 以及三個以上參數時,很可能這些參數中的一些應該被封裝爲類。例如,考慮以下兩個聲明之間的差異

Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);

通過從參數中創建對象來減少參數的數量可能看起來像是作弊,但事實並非如此。當一組變量一起傳遞時,就像上例中的x和y一樣,它們很可能是一個概念的一部分,應該有一個自己的名稱。

 


接受可變參數的函數

 

具有可變參數的函數可以接受單參數、雙參數甚至三參數。但是超過這個數量可能要犯錯。

 


 

一個函數要麼做某件事,要麼回答某件事,但不能兩者兼而有之。如果一個函數需要修改對象的狀態,或者返回關於該對象的一些信息。同時做這兩件事往往會導致混淆。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章