閱讀《代碼整潔之道》總結

 很早就閱讀過《代碼整潔之道》(英文版Clean Code),當時博主是個青澀的菜鳥,正在爲團隊創造着混亂的代碼。多年的工做中,多次被別人的代碼坑的苦不堪言,回想起當年我留下的代碼,確定也坑害了後來的同僚。當閱讀JDK源碼或者其餘優秀開源工程時,歎服做者代碼構建之精良,他們都有共同的特色:精確的變量名、恰到好處的設計模式、詳細而不贅述的註釋等等。現在重讀本書,總結一下內容並加上本身的一些看法與你們分享。java

代碼是團隊溝通方式

 工做的溝通,不僅是電子郵件或者面對面語言交流,代碼也是溝通方式之一。用代碼實現需求,只是萬里長征走完了第一步,必須讓代碼表達本身的設計思想。試想一下,你負責的功能被另一個同事接手,若是你的代碼結構清晰、註釋合理,他就不用頻繁的詢問代碼疑點,不用打斷你的工做。編寫代碼的時候,應該考慮到別人的閱讀感覺,減小閱讀障礙,爲整個團隊創造代碼,而不是你本身。程序員

讓營地比來時更乾淨

 這是美國童子軍規的諺語,美國童子軍至關於半軍事化管理的青少年夏令營。夏令營結束後孩子們離開營地,要打掃衛生保持整潔,讓營地比來時更乾淨。在軟件開發過程當中,能夠理解爲不要破壞規則,不要引入混亂。若是團隊已經制定了代碼規範,好比類名必須有子系統前綴好比BiOrderService(Bi指BI業務部門),就繼續遵循下去;再好比,團隊已經提供了公共庫好比MD5的加密,那就不要再次引入新的MD5庫。不少新手程序員接活兒後,看到不喜歡的規範就另起爐竈,須要某些工具類也不詢問老司機公共庫有沒有,直接引入本身熟悉的庫,形成兼容性或者其餘問題。apache

合適的命名

 合適的命名是頭等大事,正如給新生兒起個好名字那樣重要。不合適的命名一般是詞不達意、誤導觀衆、過分縮寫等,因爲英文並不是咱們的母語,找個合適的單詞命名彷佛真的很難。我建議是先把業務弄清楚,組織會議定下經常使用業務領域的單詞,禁止組員各自發明。好比代碼裏使用canteen表示飯堂,那就不要再發明DinnerHall,既囉嗦又誤導同僚。設計模式

看看反例:
// 手機號
String phone = 「13421800409」;
// 獲取地址
private String getDiZhi();
//修改密碼
private void modifyPassword(String password1 ,String password2)
看看正例:
// 手機號 mobileNo比phone更精確
String mobileNo= 「13421800409」;

// 避免英文拼音混雜
private String getAddress();

// 參數的命名要區分意義
private void modifyPassword(String oldPassowrd,String newPassword)

短小的方法

  方法有多短小才合適沒有定論,可是長達500行的一個方法,絕對讓閱讀者起殺人之心。過長的方法,讓閱讀者不知道從何看起,看了前面忘記後面。將複雜的方法,拆分紅邏輯相對簡單的短方法。服務器

看看反例:
//  獲取我的信息
private UserDTO getUserDTO(Integer userId)
{
    //獲取基本信息 
    … 此處寫了10行

    //獲取最近的一次訂單信息
    … 此處寫了30行

   // 獲取錢包餘額、可用優惠券張數等
    … 此處寫了30行

   return userDTO;
}
看看正例:
//  獲取我的信息
private UserDTO getUserDTO(Integer userId)
{
    //獲取基本信息 
    UserDTO userDTO= getUserBasicInfo(userId);

    //獲取最近的一次訂單信息
    userDTO.setUserLastOrder(getUserLastOrder(userId));

    // 獲取錢包、可用優惠券張數等
    userDTO.setUserAccount(getUserAccount(userId));  
    return userDTO;
}

private UserDTO getUserBasicInfo(Integer userId);
private UserLastOrder getUserLastOrder(Integer userId);
private UserAccount getUserAccount(Integer userId);

減小if/else嵌套

  爲何要減小嵌套,難道嵌套看上去不時尚嗎?我曾經看到某位同事的一段代碼嵌套達到9層,他本身再去維護的時候都看暈了。代碼過分嵌套的結果是隻有原做者才能讀懂,接盤俠一臉茫然。框架

看看反例:
// 修改用戶密碼,這個例子只有3層嵌套,很溫柔了
public boolean modifyPassword(Integer userId, String oldPassword, String newPassword) {
      if (userId != null && StringUtils.isNotBlank(newPassword) && SpringUtils.isNotBlank(oldPassword)) {
    User user = getUserById(userId);
    if (user != null) {
         if (user.getPassword().equals(oldPassword) {
              return updatePassword(userId, newPassword)
         }
     }
      }
}
看看正例:
// 修改用戶密碼 
Public Boolean modifyPassword(Integer userId, String oldPassword, String newPassword) {
     if (userId == null || StringUtils.isBlank(newPassword) || StringUtils.isBlank(oldPassword)) {
            return false;
     }
     User user = getUserById(userId);
     if(user == null) {
           return false;
      }
     if(!user.getPassword().equals(oldPassword) {
           return false;    
     }
     return updatePassword(userId, newPassword);
}

正例採用衛語句減小了嵌套,可是並不是全部場景都適合這樣改寫。若是不適合,能夠將關聯性高的邏輯抽取成一個獨立的方法減小嵌套。工具

抽離try/catch

  你們有沒有見過一個超長的方法,從頭至尾被一個try/catch照顧着?博主經歷過的項目中,這種不負責的寫法比比皆是。並不是每行代碼都會拋出錯誤,只要將會拋出錯誤的業務放在一個獨立的方法便可。ui

看看反例:
//  獲取我的信息
private UserDTO getUserDTO(Integer userId)
{
   try { 
       //獲取基本信息 
       ... 此處寫了10行
       //獲取最近的一次訂單信息.
       ...此處寫了20行
       // 獲取錢包、可用優惠券張數等
       ...此處寫了20行
    }catch (Exception e) {
        logger.error(e);
        return null;
    }
}
   return userDTO;
}
看看正例:
//  獲取我的信息
private UserDTO getUserDTO(Integer userId)
{
    //獲取基本信息 
    UserDTO userDTO= getUserBasicInfo(userId);

    //獲取最近的一次訂單信息
    userDTO.setUserLastOrder(getUserLastOrder(userId));

    // 獲取錢包、可用優惠券張數等
    userDTO.setUserAccount(getUserAccount(userId));  
    return userDTO;
}
private  UserDTO getUserBasicInfo(Integer userId);
private  UserLastOrder getUserLastOrder(Integer userId);
private  UserAccount getUserAccount(Integer userId){
      try{
          // TODO
      } catch ( Exception e) 
       { //TODO }
}

封裝多個參數

 若是方法參數將超過3個,建議放在類中包裝起來,不然再增長參數時,因爲語義的強耦合會致使調用方語法錯誤。在後臺管理中的分頁查詢接口,經常會有不少查詢參數,並且有可能增長,封裝起來是最好的。this

看看反例:
// 分頁查詢訂單 6個參數
public Page<Order> queryOrderByPage(Integer current,Integer size,String productName,Integer userId,Date startTime,Date endTime,Bigdecimal minAmount ,Bigdecimal maxAmount) {

}
看看正例:
@Getter
@Setter
public class OrderQueryDTO extends PageDTO {
 private String productName;
 private Integer userId;
 private Date startTime;
 private Date endTime;
 private Bigdecimal minAmount ;
 private Bigdecimal maxAmount;
}
// 分頁查詢訂單 6個參數
Public Page<Order> queryOrderByPage(OrderQueryDTO orderQueryDTO) {

}

第三方庫

Lombok

Lombok組件經過註解的方式,在編譯時自動爲屬性生成構造器、getter/setter、equals、hashcode、toString方法
舉例以下:
@Setter 註解在類或字段,註解在類時爲全部字段生成setter方法,註解在字段上時只爲該字段生成setter方法。
@Getter 使用方法同上,區別在於生成的是getter方法。
@ToString 註解在類,添加toString方法。
@EqualsAndHashCode 註解在類,生成hashCode和equals方法。
@NoArgsConstructor 註解在類,生成無參的構造方法。
@RequiredArgsConstructor 註解在類,爲類中須要特殊處理的字段生成構造方法,好比final和被@NonNull註解的字段。
@AllArgsConstructor 註解在類,生成包含類中全部字段的構造方法。
@Data 註解在類,生成setter/getter、equals、canEqual、hashCode、toString方法,如爲final屬性,則不會爲該屬性生成setter方法。編碼

常規寫法:
Public class Order {
     private Integer userId;
     
     public Integer getUserId() {
          return userId;
    } 

    public void setUserId(Integer userId) {
          return this.userId = userId; 
 }
}
採用Lombok:
@Getter
@Setter
Public class Order {
     private Integer userId;
}

Apache Commons系列

  Apache Commons系列組件給咱們提供了關於字符串、集合、IO操做等工具方法。這些組件是個大寶庫,提供了很多輪子。

組件 介紹
beanUtils JavaBean進行各類操做,克隆對象、屬性等等
codec 處理經常使用的編碼方法的工具類包,例如DES、SHA一、MD五、Base64等.
collections java集合框架操做
configuration java應用程序的配置管理類庫
io io工具的封裝
lang Java基本對象方法的工具類包 如StringUtils、ArrayUtils等等.
logging 提供的日誌接口
net 提供了客戶端和服務器端的數據驗證框架
看看例子:
例1: 判斷集合是否爲空:
CollectionUtils.isEmpty(null): true
CollectionUtils.isEmpty(new ArrayList()): true
CollectionUtils.isEmpty({a,b}): false

例2: 判斷集合是否不爲空:
CollectionUtils.isNotEmpty(null): false
CollectionUtils.isNotEmpty(new ArrayList()): false
CollectionUtils.isNotEmpty({a,b}): true

例3:2個集合間的操做: 
集合a: {1,2,3,3,4,5}
集合b: {3,4,4,5,6,7}
CollectionUtils.union(a, b)(並集): {1,2,3,3,4,4,5,6,7}
CollectionUtils.intersection(a, b)(交集): {3,4,5}
CollectionUtils.disjunction(a, b)(交集的補集): {1,2,3,4,6,7}
CollectionUtils.disjunction(b, a)(交集的補集): {1,2,3,4,6,7}
CollectionUtils.subtract(a, b)(A與B的差): {1,2,3}
CollectionUtils.subtract(b, a)(B與A的差): {4,6,7}
相關文章
相關標籤/搜索