阅读《代码整洁之道》总结-各种技巧分享

很早就阅读过《代码整洁之道》(英文版Clean Code),当时博主是个青涩的菜鸟,正在为团队创造着混乱的代码。多年的工作中,屡次被别人的代码坑的苦不堪言,回想起当年我留下的代码,肯定也坑害了后来的同僚。

当阅读JDK源码或者其他优秀开源工程时,叹服作者代码构建之精良,他们都有共同的特点:精确的变量名、恰到好处的设计模式、详细而不赘述的注释等等。如今重读本书,总结一下内容并加上自己的一些见解与大家分享。

代码是团队沟通方式

 工作的沟通,不只是电子邮件或者面对面语言交流,代码也是沟通方式之一。用代码实现需求,只是万里长征走完了第一步,必须让代码表达自己的设计思想。试想一下,你负责的功能被另外一个同事接手,如果你的代码结构清晰、注释合理,他就不用频繁的询问代码疑点,不用打断你的工作。编写代码的时候,应该考虑到别人的阅读感受,减少阅读障碍,为整个团队创造代码,而不是你自己。

让营地比来时更干净

 这是美国童子军规的谚语,美国童子军相当于半军事化管理的青少年夏令营。夏令营结束后孩子们离开营地,要打扫卫生保持整洁,让营地比来时更干净。在软件开发过程中,可以理解为不要破坏规则,不要引入混乱。如果团队已经制定了代码规范,比如类名必须有子系统前缀比如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(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照顾着?博主经历过的项目中,这种不负责的写法比比皆是。并非每行代码都会抛出错误,只要将会抛出错误的业务放在一个独立的方法即可。

看看反例:
//  获取个人信息
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个,建议放在类中包装起来,否则再增加参数时,由于语义的强耦合会导致调用方语法错误。在后台管理中的分页查询接口,常常会有很多查询参数,而且有可能增加,封装起来是最好的。

看看反例:
// 分页查询订单 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、SHA1、MD5、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}

作者: 编码砖家

出处:https://www.cnblogs.com/xiaoyangjia/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

本文分享自微信公众号 - DotNet程序园(dotnetblog)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Kirito的技术分享

中间件小姐姐软萌音直播—IDEA 开发部署插件

老早就听闻 ”中间件小姐姐“ 的名气,刚好这一次遇上小姐姐做直播,嗲嗲的声音真是甜得不行,要是以后都是这种软萌音来做直播,我一定准时准点抢座位并且乖乖吃下这一剂...

13710
来自专栏卯金刀GG

SSE+easyui 分页

3、mybatis的maper和xml文件对应,配置位置spring.xml 此为我备忘的记录

14520
来自专栏pangguoming

Java 获取对象全部属性 包括 父类属性

异常信息 ​ 程序会告诉你无法这么转换,所以这里要注意 ​ 第二种的参数就填你要转换的数组就可以,但是他要求数组的长度是等于链表的长度的,否则会...

33410
来自专栏呼延

Intellij Idea远程调试 Java代码

线上(真-线上/测试环境)代码出了问题,总是要在本地复现,然后debug,这个过程是在是不太友好,而且线上的很多数据本地没有,经常耽误好久的时间来同步数据.

45640
来自专栏Android技术分享

有关Android插件化的一些总结思考

最近几年移动开发业界兴起了「 插件化技术 」的旋风,各个大厂都推出了自己的插件化框架,各种开源框架都评价自身功能优越性,令人目不暇接。随着公司业务快速发展,项目...

13420
来自专栏Spring相关

mybatis插入数据后返回自增主键ID详解

​ 开发过程中我们经常性的会用到许多的中间表,用于数据之间的对应和关联.这个时候我们关联最多的就是ID,我们在一张表中插入数据后级联增加到关联表中.我们熟知...

2K20
来自专栏猿码优创

用java写了一个飞龙腾云

13420
来自专栏happyJared

String 类和常量池

尽量避免多个字符串拼接,因为这样会重新创建对象。如果需要改变字符串的话,可以使用 StringBuilder 或者 StringBuffer。

16520
来自专栏猿码优创

Python环境搭建以及入门

2018年5月,PYPL发布了世界编程语言流行指数榜,python首次超越Java占据榜首。

13830
来自专栏C# 编程

c#六大设计原则(以仪器代码为例)

使用C#编程方式,并结合仪器(Instrument)编程,对以上设计原则进行讲解。

11610

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励