《代碼整潔之道》部分筆記

1、命名

  • 名副其實:讓讀者看名字就明白它的作用
  • 避免誤導:不要用有歧義的詞語,例如不是List就不要帶有List
  • 有意義的區分:不要加一些廢話,例如NameString,例如ProductData和ProductInfo,不能區別它們的作用。
  • 使用讀得出來的名稱:使用英語單詞
  • 使用可搜索的名稱:不要使用a、b、c這種變量名,使用便於搜索的名字
  • 避免使用編碼:不要加一些無意義的前後綴
  • 避免思維映射:不要使用l、O這種名字(與1,0相近),儘量少的引起歧義。
  • 類名:應該命名爲名詞或名詞短語
  • 方法名:應該命名問動詞或動詞短語
  • 每個概念對應一個詞:同樣的功能對應一個名字,不要出現一會用manager,一會用controller的情況
  • 別用雙關詞:遵循一語一意的原則,如果連接用了add,那麼添加就別再用add,可以用append或insert
  • 使用專業名稱:例如使用JobQueue等,帶有含義與數據結構的詞語,讓程序員一看就明白它的意思
  • 添加有意義的語境:state,很難之道它的含義,如果它代表的是地址的state,可以加上前綴語境addrState
  • 不要加無意義的語境

2、函數

  • 短小:函數儘可能的短
  • 只做一件事:只做一件事,完成在同一抽象層次下的一些步驟完成一項工作。例如人是一個層級,四肢是更低的層級,手指又是更低的層級。
  • 每個函數一個抽象層級:1、不要在一個函數內混雜不同層級的操作,2、自頂向下的規則,順着抽象層級結構寫函數。
  • Switch語句:違反了單一權責原則、開放閉合原則,解決方法:放在工廠類用,利用接口多態派遣。
    • 單一權責原則:一個類負責一個功能
    • 開放閉合原則:對擴展開放,對修改關閉,通過擴展來修改,而不是修改原代碼
  • 使用描述性名稱:名字要表達函數的功能,不用怕長,長而清晰的名稱,比短而費解的名稱好。
  • 函數參數:函數的參數應該越少越好,而且應該讓人看到名稱和參數,就大概清楚函數的作用,幾種參數的情況:
    • 一元函數:有三種情況,一二種比較普遍
      • 詢問該參數一些問題:例如 boolean fileExists(“MyFile”)
      • 將參數進行轉換:例如 InputStream fileOpen(“MyFile”)
      • 事件,通過參數修改系統狀態:例如 void passwordAttemptFailedNtimes(int attempts)
    • 不要傳入標識參數:例如render(Boolean isSuite),有這種情況,將函數拆分成兩個renderForSuite() 和 renderForSingleTest()
    • 二元函數:
      • 兩個值有自然順序,組成一個整體,例如笛卡爾座標的x,y值
      • 儘量寫成一元函數,例如writeField(outputStream, name),儘量寫成 outputStream.writeField(name)
      • 需要兩個參數時,利用函數名減少記憶參數順序負擔,例如assertExpectedEqualsActual(expected, actual)
    • 三元函數:儘量少用,可以將多個參數封裝成類,通過名字提示內容,減少記憶參數順序的負擔。
  • 無副作用:不要在函數中加別的操作,遵循只做一件事的原則,也不要把參數用作輸出
  • 分割指令與詢問:例如需要一個參數決定是否執行,不要在一個函數內既做詢問,又做設置,應分開它:
if(attributeExists("username")){
	setAttribute("username", "unchebob");
}
  • 使用異常替代返回錯誤碼:當指令函數返回錯誤碼時,不要用太多if-else嵌套,放在一個try-catch模塊中
  • 抽離try-catch代碼塊:儘量將try-catch代碼抽離爲單獨一個方法,與正常流程區分開來。錯誤處理就是一件事,錯誤處理的函數應該遵循只做一件事的原則,只處理錯誤函數
  • 減少重複:不要重複算法,公有相同的操作應該抽離出來。

3、註釋

儘量不要寫註釋,用代碼來解釋意圖

4、格式

  • 垂直格式:
    • 整體的順序應該是先給出高層次的概念和算法,細節逐漸展開
    • 垂直方向上,概念相近的靠近
    • 垂直上的順序是,調用者儘可能放在被調用者上面
    • 垂直上封包聲明、倒入聲明、每個函數之間用空行隔開
  • 橫向格式:
    • 空格用於加強分割作用,等號的兩邊是不同的要素,加空格起到分割的作用,而函數名和括號之間是一個整體,不加空格。
    • 空格另一種用法是強調運算順序,b*b - 4*a*c 這樣就會比較清晰,看出左右部分,遵循先乘除後加減的運算順序。

5、對象和數據結構

  • 類應該暴露抽象接口。用戶無需瞭解數據實現就能操作數據本體。
  • 過程式編程和麪向對象式編程:
    • 過程式:類與方法分開,一個方法針對不同的類實現不同的邏輯,添加新的方法不需要修改類,但是添加新的類就要修改所有現有的方法。
    • 面向對象:類中繼承接口,實現抽象方法,優點是添加新的類不需要修改現有的方法,但是添加新的方法就要修改所有的類。
    • 小結:處理問題時需要分情況討論,過程式的編程添加新的方法比較方便,而面向對象的編程添加新的類比較方法
  • 得墨忒耳律:類C的方法f只應該調用以下對象的方法:
    • C
    • 由f創造的對象
    • 作爲參數傳遞給f的對象
    • 由C實體變量持有的對象
  • 數據傳送對象:
    • DTO是隻有公共變量(包括私有變量+公共getter/setter)、沒有函數的類,是最精煉的數據結構。
    • Active Record是一種特殊的DTO形式,同時也會擁有save、find方法,通常是對數據庫或其他數據源的之間翻譯(就是我們項目中的Domain Object,一個類對應數據庫一張表)。Active Record往往被塞進業務規則方法,導致數據結構和對象的混雜體。
    • 應該把Active Record當成數據結構,另外創建包含業務規則、隱藏內部數據的獨立對象。

6、類

  • 類的組織:
    • 變量順序:公共靜態、私有靜態、私有實例變量
    • 公共函數跟在變量之後,把公共函數調用的私有函數放在公共函數後面,滿足自頂向下的原則,讀起來像一張報紙
  • 類應該短小:遵循單一權責的原則,一個類負責一個權責
  • 內聚:把大的方法進行拆分,如果一些方法只被少數的變量用到,就應該拆分處一個類。保證類的內聚性,類的變量被類中的方法所使用。
  • 爲修改而組織:需要添加功能時,可以通過子類實現這項功能,滿足開放閉合原則,對修改關閉,對擴展開放。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章