代码简洁之道

如题,最近在优化代码,感觉代码优美要比实现功能更需功力,摘选一些前辈的文章,整理如下,

公用组件部分

这是美国童子军规的谚语,美国童子军相当于半军事化管理的青少年夏令营。夏令营结束后孩子们离开营地,要打扫卫生保持整洁,让营地比来时更干净。在软件开发过程中,可以理解为不要破坏规则,不要引入混乱。如果团队已经制定了代码规范,比如类名必须有子系统前缀比如BiOrderService(Bi指BI业务部门),就继续遵循下去;再比如,团队已经提供了公共库比如MD5的加密,那就不要再次引入新的MD5库。很多新手程序员接活儿后,看到不喜欢的规范就另起炉灶,需要某些工具类也不询问老司机公共库有没有,直接引入自己熟悉的库,造成兼容性或者其他问题。

合适的命名

合适的命名是头等大事,正如给新生儿起个好名字那样重要。不合适的命名通常是词不达意、误导观众、过度缩写等,由于英文并非我们的母语,找个合适的单词命名似乎真的很难。我建议是先把业务弄清楚,组织会议定下常用业务领域的单词,禁止组员各自发明。比如代码里使用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(userId);
Private  UserLastOrder getUserLastOrder(userId);
Private  UserAccount getUserAccount(userId);

减少if/else嵌套

为什么要减少嵌套,难道嵌套看上去不时尚吗?我曾经看到某位同事的一段代码嵌套达到9层,他自己再去维护的时候都看晕了。代码过度嵌套的结果是只有原作者才能读懂,接盘侠一脸茫然。减少if/else嵌套这里我会另开一篇细讲

看看反例:

// 修改用户密码,这个例子只有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照顾着?博主经历过的项目中,这种不负责的写法比比皆是。并非每行代码都会抛出错误,只要将会抛出错误的业务放在一个独立的方法即可。

看看反例:

//  获取个人信息
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(userId);
Private  UserLastOrder getUserLastOrder(userId);
Private  UserAccount getUserAccount(userId){
      try{ // TODO } catch( Exception e) { //TODO}
}

封装多个参数

如果方法参数将超过3个,建议放在类中包装起来,否则再增加参数时,由于语义的强耦合会导致调用方语法错误。在后台管理中的分页查询接口,常常会有很多查询参数,而且有可能增加,封装起来是最好的。

看看反例:

// 分页查询订单 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) {

}

优质的第三方库 Apache Commons系列

Apache Commons系列组件给我们提供了关于字符串、集合、IO操作等工具方法。这些组件是个大宝库,提供了不少轮子。

看看例子:

例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}

这里不推荐使用lombok ,因为会引起对它的依赖,不够灵活.

还有,推荐使用lambda表达式和Stream流进行一些逻辑处理,也会使代码更为简洁

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值