代码坏味道:语句篇

1 滥用控制语句

产生的原因:

和长函数产生的原因类似,平铺直叙地写代码,一点一点追加代码,没有遵循童子军军规,没有做到分离关注点。

坏味道:
  • 嵌套的代码;
  • else 语句;
  • 重复的 switch;
  • 循环语句。
存在的问题:

真正的问题在于它们会使代码变得复杂,超出人脑所能理解的范畴。

解决方案:
  • 通过提取单个元素操作,降低循环语句的复杂度;
  • 用卫语句来简化条件表达式的编写,降低选择语句的复杂度;
  • 对于重复的 switch 本质上是缺少了一个模型,可以使用多态取代条件表达式,引入缺少的模型,消除重复的 switch。

一个衡量代码复杂度的标准是圈复杂度,我们可以通过工具检查一段代码的圈复杂度。

编程规则:
  • 函数至多有一层缩进;
  • 不要使用else关键字。

2 与封装有关的坏味道:过长的消息链和基本类型偏执

坏味道:
  • 过长的消息链,或者叫火车残骸——一行代码中是否出现了连续的方法调用
  • 基本类型偏执。
解决方案:
  • 火车残骸的代码就是连续的函数调用,它反映的问题就是把实现细节暴露了出去,缺乏应有的封装,而产生了耦合。
    重构的手法是隐藏委托关系,实际就是做封装,做到解耦。编程指导原则:迪米特法则。
  • 基本类型偏执就是用各种基本类型作为模型到处传递,这种情况下通常是缺少了一个模型。
    解决它,常用的重构手法是以对象取代基本类型,也就是提供一个模型代替原来的基本类型。
    基本类型偏执不局限于基本类型,字符串也是这种坏味道产生的重要原因,再延伸一点,集合类型也是。编程规则:封装所有的基本类型和字符串。
请记住一句话:

构建模型,封装散落的代码。

坏味道之火车残骸示例:
String name = book.getAuthor().getName();

注意,当你必须要首先了解一个类的细节,才能写出代码时,这只能说明一件事,这个封装是失败的。

我们很多程序员对封装的理解一直停留在数据结构加算法的层面,这使暴露细节成了常态,而封装反倒成了稀缺。而要想摆脱初级程序员的水平,就要先从少暴露细节开始。

重构之后:

class Book {
...
public String getAuthorName() {
return this.author.getName();
}
...
}


String name = book.getAuthorName();
坏味道之基本类型偏执示例:
public double getDisplayPrice() {
    BigDecimal decimal = new BigDecimal(this.price);
    return decimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
}

重构之后:

class Price {
    private long price;

    public Price(final double price) {
        if (price <= 0) {
            throw new IllegalArgumentException("Price should be positive");
        }
    
        this.price = price;
    }
}

一旦有了这个模型,我们还可以再进一步,比如,如果我们想要让价格在对外呈现时只有两位,在没有 Price 类的时候,这样的逻辑就会散落代码的各处,事实上,代码里很多重复的逻辑就是这样产生的。而现在我们可以在 Price 类里提供一个函数:

public double getDisplayPrice() {
    BigDecimal decimal = new BigDecimal(this.price);
    return decimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
}

你可能感兴趣的:(代码坏味道:语句篇)