常见的代码坏味道以及解决方式

393 阅读3分钟

通用步骤

1.首先应该阅读代码,理解代码的基本含义。
2.对原本的代码编写单元测试,如果测试能通过,进行commit。
必须要有单元测试!!!单元测试全部通过才算重构完成!!!

神秘命名(Mysterious Name)

方法或变量名不表义,很难看懂是什么意思
3.利用ide重构原有的神秘命名代码。
4.跑测试,如果测试能通过,则变更引用原代码的位置的引用方法。
5.如果测试通过,小步提交commit。

image.png

重复代码(Repeat Code)

两个或多个函数包含了多行重复代码
3.利用ide重构原有的重复代码,抽出为公共方法。
4.将原有的重复代码替换为公共方法,跑测试。
5.如果测试通过,小步提交commit。

image.png

过长函数(Long Function)

单一函数过长
3.对原本过长函数中的逻辑,按照其做的事情进行抽取,抽成符合其名字的小方法。
4.跑测试。
5.如果测试通过,小步提交commit。

image.png

过长参数列表(Long Parameter List)

常见的坏参数有
1.标记参数,例如isXXX这种变量,实际上一个函数方法中可能就包含了两种逻辑,在这种情况下,完全可以将两种逻辑分离,写为两个单独的方法,增加代码可读性。
2.通用性变量,实际上可以将多个参数的变量抽取到一个类中,与业务无关的逻辑也可以在类中实现。

image.png

全局数据(Global Data)

全局都能用到的数据,或者说全局都可能会用到的数据,不能提供其对外暴露的修改接口,因为全局都能进行调用修改的情况下,定位问题将变成一件非常困难的事情。

image.png

可变数据(Mutable Data)

image.png

发散式变化(Divergent Change)

一个函数中包含了多条逻辑,如果需要进行修改,例如一个商品计算价格,首先计算总价,然后计算折扣后价格,如果都放在同一个函数中,那么如果计算逻辑改变,就需要在大函数中进行修改,在此过程中可能计算会出现问题,因此可以将计算总价,计算折扣价格抽取成两个不同的方法,如果后期业务逻辑改变只需要修改两个对应小方法中的代码即可。 其实这就是面向对象设计原则中的单一职责原则

image.png

依恋情节(Feature Envy)

一个类中的成员变量包含了另一个类的对象,且针对这个对象实现了某一个具体函数方法,那么此时的函数方法就应该转移到另一个类中,在类中只需要通过其对象调用方法即可。

image.png

数据泥团(Data Clumps)

例如以下这个person类,函数telephoneNumber由officeAreaCode和officeNumber组成,那么如果officeNumber被删除,telephoneNumber也就失去了他的意义,且所有引用到它的地方都会出现问题,这样的情况就是数据泥团,即多个数据混合在一起

class Person {
  constructor(name) {
    this._name = name;
  }

  get name() {
    return this._name;
  }

  set name(arg) {
    this._name = arg;
  }

  get telephoneNumber() {
    return `(${this.officeAreaCode}) ${this.officeNumber}`;
  }

  get officeAreaCode() {
    return this._officeAreaCode;
  }

  set officeAreaCode(arg) {
    this._officeAreaCode = arg;
  }

  get officeNumber() {
    return this._officeNumber;
  }

  set officeNumber(arg) {
    this._officeNumber = arg;
  }
}

对于这种情况我们可以将两个强关联的变量抽取到一个类当中。 image.png

基本类型偏执(Primitive Obsession)

image.png

循环语句(Loop)

尽可能的使用Stream流进行逻辑处理

image.png