3
头图

初学者在学习了语法和一堆的 API 之后,就会尝试自己写一些具有完整功能的程序。这个过程当中很容易养成写一个上百行甚至几百行的方法的习惯。总的来说,这是思维当中缺少抽象、设计和封装的表现。随着编程经验的丰富,总会有克服的一天。

但如果想尽早克服这种情况,像专业程序员那样去思考,那么要多读一些设计代码可读性方面的书。业界有很多经典的书,比如《设计模式》、《重构》、《代码整洁之道》、《实现模式》等。我强烈推荐这四本,因为我个人从中受益匪浅,觉得它们都是必读的。

当一个屏幕装不下你的方法体时,就要当心了。

长方法的坏处非常多,主要体现在以下几个方面:

一、长方法中会包含特别多的变量。

长的方法逻辑多,变量自然也多。太多的变量经常会伴随下面的问题:

1、命名困难。当你要定义4个元素类型为 UnfinishedCustomOrder 的 List,以及4个元素类型为 FinishedCustomOrder 的 List 时,这些变量的名字会非常长,而且眼神不好的话,后面还容易用错,出现 bug。

2、重(chong)用变量。 初学者对变量的命名存在随意性,同时使用变量也存在随意性。比如定义一个 boolean flag 变量,在这段逻辑里面用过一遍,然后在那段逻辑里面再用一遍。

3、重复的变量。 一个方法长到一定程度后,经常会出现写到后面忘了前面的情况。于是出现比如说,又重新去数据库查询之前已经查过一次的内容的情况。这种现象特别容易出现在反复修改过多次,而且每次都是不同的人来改的代码中。

4、改了变量内容但是忘了。 比如下面这种:

public void processAllOrders() {
    List allOrders = ...;  // 查询所有订单
    ...
    // 排除掉已完成订单。注意这条语句甚至可能被委托到
    // 另一个方法执行,本方法中完全看不到。
    allOrders.removeAll(finishedOrders); 
    ...
    ... // 两百行代码后
    ...
    ...
    ...
    // 此时另一个程序员接手实现需求变更。他只关注这部分要改的,
    // 仅看变量名就认为 allOrders 依旧包含所有订单,于是出错
    allOrders.forEach(order -> {...});
    ...
}

这属于严重违反编码原则的情况。有人说,是不是接手的这个程序员阅读代码不认真啊?请注意,阅读代码本身是非常消耗心智的。读代码不是读小说,要严丝合缝的理解代码的行为。如果代码可读性很差,那么理解出错的机率自然也会大,更别说上面的例子中,变量名存在误导性,这能怪阅读者吗?

二、长方法会有很多出口。

一个长方法的执行过程实际上是分几个阶段完成的,每个阶段可能有自己的远程调用、数据校验和抛出异常,这会导致长方法中有很多出口。一个方法有多个出口,大多数情况下是不好的编程习惯,主要体现在:

1、调试断点会出现不确定性。 比如你在某行打了个断点,但调试的时候发现没有执行,因为方法在这之前就通过某个出口结束了。反复尝试寻找断点降低了开发效率。

2、反复构建返回值。 如果方法是有返回值的,那么多个出口的返回值当然是不一样的,它们的前面必然会出现相同的构建这些返回值的过程。一旦这个过程需要改动,那么遗漏某处就意味着BUG。

3、有的 return 语句写在层层缩进当中,会给阅读带来困难。 因为当你读到这里时,会发现脑海中构建的一层层的逻辑,到了这里突然被彻底中断了,在某个场景下,方法在这里结束。于是你必须牢记,后面的代码中的所有逻辑都要排除这个场景。这样的结束若再来个两三次,恐怕能把你逼疯。

我之前说的是大多数情况。那么剩下的情况是指什么呢?主要是校验方法,比如:

public boolean validate(Order order) {
  if (order == null) {
    return false;
  }
  if (order.isCancelled()) {
    return false;
  }
  ...
  return true;
}

此类方法有多个出口我觉得是可以接受的。

三、阅读长方法非常费神。

我们阅读方法时,会在脑海中构建每个参数和变量,理解它们的演变过程。这个时候每多一个变量,都是增加了一分脑力负担。要知道,人与人之间的脑力承受能力是不同的,就算同一个人,在不同的精神状态下的承受能力也有差别。所以,如果一个软件产品或项目,想要在整个生命周期中减少出错的可能,那么就有必要提升代码可读性,换句话说,就是减少阅读代码的脑力负担。代码可读性是风险控制的一部分,长方法为项目增加了风险。

如何克服

上面说的就是一个方法太长会带来哪些问题。要克服的话,首先是看我最开始推荐的那几本书,其次是培养自己的抽象思维,从具体的功能中提取出多个层次的抽象逻辑,将功能的实现拆分到不同的抽象层。


捏造的信仰
2.8k 声望272 粉丝

Java 开发人员