重构带来的好处为何?如何重构?

2023年3月3日

💎 加入 E+ 成長計畫 與超過 350+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

什么是重构?

重构 (Refactoring)指的是「在不改变外部行为的情况下,重组代码的过程」,因此对于外部用户而言,重构与否是没有感觉的,但重构的好处在于:

  • 提高可读性:通过重构,代码变得更加清晰、简洁,并且具有更好的组织结构,从而提高可读性和理解难度。
  • 提高可维护性:重构后的代码更加清晰,易于理解和修改,这有助于维护。
  • 减少冗余:重构可以删除无用的代码、合并重复的代码和重新组织代码,从而减少代码冗余。
  • 提高性能:重构可以帮助提高代码性能,例如通过减少循环次数和使用更高效的数据结构等。
  • 改善安全性:通过重构,可以删除容易被攻击的代码,提高代码的安全性。

何时该重构?

重构是一个持续发生的过程,而遇到以下的状况时,都很适合开始着手重构:

  1. 代码重复:通过重构可以消除重复的代码,使代码库更加简洁。
  2. 技术债务:随着时间的推移,代码库可能变得混乱且难以维护,导致技术债务的累积。通过改善代码的结构和组织,重构可以减少这种债务。
  3. 添加新功能:在给现有代码添加新功能时,重构可以确保代码仍然易于维护和可扩展。
  4. 性能优化:如果代码运行过慢或需要太多资源,重构可以通过解决瓶颈和低效率来提高性能。
  5. 错误修复:重构可以使得更容易找到并修复代码中的错误,同时防止新的错误被引入。
  6. 团队合作:如果多个开发人员正在对同一代码库进行工作,重构可以通过使代码更容易理解和维护来提高合作。

如何重构?

好的重构建议是能够切得够小去做,并且不影响到外部行为,这里介绍几个常见的技术:

Red-Green-Refactor

Red-Green-Refactor 是一种软件开发流程,通常用测试驱动开发 (TDD),此流程分成三个步骤:

  • Red(红色):开发人员首先编写一个失败的测试,以验证所需的功能不存在或不正确。
  • Green(绿色):开发人员接着编写最少的代码来通过测试。
  • Refactor(重构):开发人员再次检查代码,以确保其结构正确、可维护和易于理解。
Red-Green-Refactor
Red-Green-Refactor
圖片來源:https://www.altexsoft.com/blog/engineering/code-refactoring-best-practices-when-and-when-not-to-do-it/s

如上图所示,通过这种方式,开发人员可以保证代码符合标准,同时避免因复杂的代码而导致的混乱。这种方法有助于确保代码质量,并通过经常测试来确保程序的正确性。

抽象化(Abstraction)

如果有很多地方需要做重构,可以用抽象化(Abstraction)的方式来做类继承、层次结构和提取,目标是减少重复且不必要得代码。

Pull-Up and Push-Down
Pull-Up and Push-Down
圖片來源:https://www.altexsoft.com/blog/engineering/code-refactoring-best-practices-when-and-when-not-to-do-it/

上图为 Pull-UpPush-Down 的方法,Pull-Up 是将方法从子类移动到父类,Push-Down 则是将方法从父类别移动到子类别。

合成方法(Composing Method)

  1. Extract Method:如果有一段代码能够被独立出来,则将它放到独立的函数中,并让函数名称解释该函数用途。下方有重构前后的范例。

原来的代码为:

void Process(MyDataSet mds) {
 int result = 0;
 if (mds.isReady) {
  int data1 = mds.param[0];
  int data2 = mds.param[1];
  result = data1 % data2;
 }
}

重构后的代码为:

void Process(MyDataSet mds){
 int result = 0;
 if (mds.isReady)
  result = CalculateMDS(mds.param[0], mds.param[1]);
}
int CalculateMDS(int data1, int data2) {
  return data1 % data2;
}

可以将不易理解的代码,放入新方法中,并且取一个有意义的命名,这样可以提高可读性和可维护性。

  1. Inline Method: 在函数调用的地方,直接插入函数本体,并且移除函数。下方有重构前后的范例。

原来的代码为:

class PizzaDelivery {
  // ...
  int getRating() {
    return moreThanFiveLateDeliveries() ? 2 : 1;
  }
  boolean moreThanFiveLateDeliveries() {
    return numberOfLateDeliveries > 5;
  }
}

重构后的代码为:

class PizzaDelivery {
  // ...
  int getRating() {
    return numberOfLateDeliveries > 5 ? 2 : 1;
  }
}

如果有些函数里面的代码,和函数名其实同样的清晰易懂,就可以直接去掉函数就好。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們