队友代码分析

前言

在最近的结对项目中,需要分析队友的个人项目代码并发表博客,在此说明
下面是我个人的分点分析好友代码的优缺点



优点

1. 接口的使用

在这里插入图片描述
在他的代码中,非常人性化地使用了接口来定义所有的功能。我作为第三视角,查看他的代码时,第一反应就是去查看他的接口定义了些什么方法,以及各个方法的功能如何。这对我接下来的代码阅读有不小的帮助



2. 方法名、变量名命名见名知意

另一个增加代码阅读性的优点是:方法名命名规范,并且见名知意
在他的代码中,方法名大多都是一些通俗易懂的动词短语,如:

 void paperCreate(int num);
 String getSeniorOperation(int mode);
 int getOperateNum();

这样的动词短语,即使没有看代码注释,也能通过上下文来猜测和验证该方法的功能

以及下方的变量名,即使我没有找到该变量的定义,我也能够判断出这个变量的功能是来区分是否添加左右括号的

if (!useBrackets){...}


3. 合适的代码注释

正如我们慕课中所介绍的那样,很多时候很多同学写代码注释的时候,都希望尽可能将每一行代码都添加上注释,来使得代码阅读者理解代码。然而这样的编码方式,更多情况下会使得代码十分凌乱、冗杂,甚至看起来不爽。
因为代码也是有语义的,所以并不需要将每行代码都添加上注释,只需要在关键位置处添加上注释即可。

下面是截取出来的一个方法的前半部分

  • 在方法前,有这个方法的简要文档注释介绍,通过方法名我们也知道这个方法是用来获取括号的
  • 在if语句中的变量名已经能够使我们知道该语句的含义,所以无需注释
  • 最重要的注释在于if (random.nextInt(5) == 0)处,该段代码几乎没有任何语义,编者在此给出注释:这里随机数的范围也是为了控制括号出现的概率使人一目了然
 /**
  *随机插入一个左右括号。
  * @return 返回一个字符串,为左括号或者右括号
  */
 public String getBrackets() {
 Random random = new Random();
    if (!useBrackets) {
      // 这里随机数的范围也是为了控制括号出现的概率
      if (random.nextInt(5) == 0) {
        useBrackets = true;
        return "(";
      } else {
        return "";
      }
    }


4. 符合Google代码规范

所有的变量命名、方法命名、块缩进、自动换行、水平空白等都符合Google代码规范







缺点

1. 功能的定义实现都在一个类中完成(万能类)

仔细查看他的代码结构:

  • Function类:实现所有的功能
  • AutoPaper类:程序的入口(main函数)

在这里插入图片描述
所有的代码都在Function中完成,没有将逻辑分层、代码分块的思想。这种万能类在编写小规模的项目时可以十分迅速简便,一旦项目的规模增大,那么该代码的维护是十分困难的。
缺点如下:

  • 代码耦合度过高:当更改某一个方法时,可能需要更改Function类中的其他很多方法
  • 无法理清代码逻辑:Function类中的方法的依赖关系不容易确定。当方法增多时,无法理解是A方法应该先执行还是B方法先执行。程序员很容易陷入逻辑错误中
  • 无法找到程序出错的原因:当万能类中的某一个方法出错时,无法像分层式一样,找到具体层的错误,再找到该层中的某个逻辑错误。程序员只知道Function类中的方法出错了,但具体是哪里出错、为何出错将一无所知



2. 错误的异常处理思维

在编写大型项目时,异常处理是十分重要的。所以我也重点查看了下每个类、每个方法的异常处理。于是我惊人的发现,没有一个方法有throws

简单地来说,就是碰到异常就try catch。这也导致他的代码十分冗长,大半部分都是try catch
正确的方式应该是:

  • 对于功能型的方法,除非没有其他方法会调用它,尽量将异常throws,交给上层进行处理
  • 对于调用型的方法(即根据不同的情况,调用其他功能型方法的方法),使用try catch处理被调用的功能型的方法所抛出的异常



3. 没有考虑性能优化

首先观察以下代码:

  /**
   *随机出一道题
   *@return 返回一个字符串,表示出的题目
   */
  public String getQuestion() {
    useBrackets = false;
    Random random = new Random();

这个方法是用来获取一道题目的。在试卷生成过程中,这个方法会被多次调用,而每次调用都会执行Random random = new Random();来获取Random对象。当试卷题目增加、试卷数目增多,每次都去new一个对象,这对性能是一个不小的消耗。

正确的方式应该是在类被加载的时候,就让其创建好一个Random对象,以后每次调用方法时,使用该对象就可以了。



4. 应尽可能避免可能出现的异常

对于该代码:if (!kindOfStudent.equals("小学")),很显然,如果当kindOfStudent == null成立时,该段代码会产生空指针异常,为程序运行增加了不必要的异常。

对于String的equals方法,我们应该尽量将非空字符串放在调用者的位置,最好是将字面常量放在调用者的位置,如:if (!"小学".equals(kindOfStudent))



5. 应遵循接口式编程

在编写功能方法时,应关注:该方法的作用、该方法传入的参数、该方法执行后的结果,拿到结果之后,再去做其他的事

观察下面的方法:

  /**
   *登录功能
   */
  public void login() {

这个方法是用于处理登录逻辑,然而这个方法没有任何返回值。如果这个方法出现在某个框架的API中,调用者会十分疑惑:为何登录功能的返回值是void,难道不应该是boolean吗?这就是问题所在,这个方法处理后的结果应尽可能地返回给程序,而不是一股脑将所有的工作全部处理掉。



6. 没有任何测试

在队友的工程中,没有任何的测试文件和单元测试。这是一个很不好的习惯,测试也是项目的一部分,不应该将其舍弃。
并且合理地编写测试方法能够减少后期维护的代价,例如在我的项目中就大量的编写了测试文件:
在这里插入图片描述
当我需要修改某一个方法时,很多时候我都不需要重新编写测试文件,直接调用原先编写的就可以了。因为方法的功能没有变化,只是逻辑变化了,最后只需要观察结果是否符合预期即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值