【前端】重构,有品位的代码 07 ── 简化条件逻辑

开发 架构
在程序编写中,复杂的条件逻辑会导致算法复杂度上升,因为会根据不同的条件分支做出不同的事情,这样便得到复杂冗长的函数。正如你所知道的,函数越大越长,代码的可读性就越低,在理解和阅读就愈发困难。

[[410522]]

本文转载自微信公众号「前端万有引力」,作者一川。转载本文请联系前端万有引力公众号。

简化条件逻辑

常见的简化条件逻辑方法有:

  • 分解条件表达式
  • 合并条件表达式
  • 以卫语句取代嵌套条件表达式
  • 以多态取代条件表达式
  • 引入特例
  • 引入断言

1. 分解条件表达式

在程序编写中,复杂的条件逻辑会导致算法复杂度上升,因为会根据不同的条件分支做出不同的事情,这样便得到复杂冗长的函数。正如你所知道的,函数越大越长,代码的可读性就越低,在理解和阅读就愈发困难。

在前面几篇文章中,对于大块头函数可以根据功能意图分解成几个小型的函数,因此可以根据逻辑分支的意图将条件逻辑函数分解。

原始代码:

  1. if(!have.before(plan.summerStart) && !plan.after(plan.summerEnd)){ 
  2.   charge = quantity * plan.summerRate; 
  3. }else
  4.   charge = quantity * plan.regularRate + plan.regularServiceCharge; 

重构代码:

  1. charge = summer() ? summerCharge() : regularCharge(); 
  2.  
  3. function summer(){ 
  4.   return !have.before(plan.summerStart()) && !have.aftet(plan.summerEnd()); 
  5.  
  6. function summerCharge(){ 
  7.   return quantity * plan.summerRate; 
  8.  
  9. function regularCharge(){ 
  10.   return quantity * plan.regularRate + plan.regularServiceCharge; 

2. 合并条件表达式

在进行代码的条件检查,检查条件虽有不同,但是处理事件的行为却是一致的。与其使用条件逻辑处理事件,不如使用逻辑『或』和『与』将其合并成条件表达式,分解冗长的函数代码。使用条件表达式可以让代码阅读更清晰,提炼函数可以将条件函数的代码逻辑提炼成独立函数,可理清代码意义。

具体的,进行合并条件表达式之时,必先确定其是否具有副作用,将查询函数和修改函数分离处理。使用适当的逻辑运算符,将两个逻辑条件表达式合并成一个。

原始代码:

  1. if(employee.seniority < 2) return 0; 
  2. if(employee.months > 12) return 0; 
  3. if(employee.timereturn 0; 

重构代码:

  1. function func(){ 
  2.   return (employee.seniority < 2) || (employee.months > 12) || employee.time
  3.  
  4. if(func()) return 0; 

3. 以卫语句取代嵌套条件表达式

在条件表达式中通常有两个风格:两个条件分支都属于正常行为,可以使用if...else...;只有一个条件分支时正常行为,另一个分支则是异常行为,即出现某个罕见条件应该单独检查(此为『卫语句』),条件为真时立刻从函数中返回。

所谓『卫语句』取代嵌套条件表达式,就是给其中的某分支给予特别的重视。其实就是对条件语句不是一视同仁,而是倚重其中最重要的分支语句,让读者阅读代码时能够一眼便能看透逻辑。

原始代码:

  1. function payMount(){ 
  2.   let result; 
  3.   if(isDead){ 
  4.     result = amountFunc(); 
  5.   }else
  6.     if(isSeparated){ 
  7.       result = separatedAmout(); 
  8.     }else
  9.       if(isRetired){ 
  10.         result = retiredAmount() 
  11.       }else
  12.         result = normalAmount(); 
  13.       } 
  14.     } 
  15.   } 
  16.   return result; 

重构代码:

  1. function payMount(){ 
  2.   if(isDead) result = amountFunc(); 
  3.   if(isSeparated) result = separatedAmout(); 
  4.   if(isRetired) result = retiredAmount(); 
  5.   return normalAmount(); 

4. 以多态取代条件表达式

在编程中复杂的条件逻辑是相当难理解的代码,与其寻求给条件逻辑添加结构,不如拆分分支条件到不同的场景,即高阶用例。在拆解复杂的条件逻辑时,有时发现条件逻辑本身结构足以表达,但使用类和多态能把逻辑拆分表达更清晰。

如果现有的类尚不具备多态行为,可创建工厂函数返回恰当的对象实例,在调用方法时即可获得对象实例。可以将带有条件的函数移到超类中,如果条件逻辑还未提炼到独立的函数。任选子类在其中创建函数,将其进行覆写超类中容纳条件表达式的函数,将子类相关条件表达式分支复制到新函数进行调整。

原始代码:

  1. switch(user.type){ 
  2.   case "UserName"
  3.     return "yichuan"
  4.   case "UserAge"
  5.     return this.age > 18 ? "成年" : "未成年"
  6.   case "UserUniversity"
  7.     return this.score > 600 ? "985高校" : "非985高校"
  8.   default
  9.     return "unknown"

重构代码:

  1. class UserName{ 
  2.   get detail(){ 
  3.     return "yichuan"
  4.   } 
  5.  
  6. class UserAge{ 
  7.   get detail(){ 
  8.     return this.age > 18 ? "成年" : "未成年"
  9.   } 
  10.  
  11. class UserUniversity{ 
  12.   get detail(){ 
  13.     return this.score > 600 ? "985高校" : "非985高校"
  14.   } 

5. 引入特例

常见的重复代码是:一个数据结构的使用者都在检查某个特殊的值,且当这个特殊值出现时多做的处理也同样。如果发现代码中在多处以相同方式应对同个特殊值,就可以将处理逻辑整合在一块。

处理重复代码最好的方法时使用『特例』模式,创建一个特例元素,用来处理特例的共用行为,可用一个函数调用取代部分特例检查逻辑。

通常的,特例有几种表现形式,我们可以对常见方式进行处理。如:

  • 只从对象中读取数据,可以提供一个预先填充值的字面量对象
  • 除获取简单数值外还需更多行为,则可以创建保函所有共有行为所对应的函数
  • 特例对象可以封装成类进行返回,亦可通过变换插入数据结构
  1. //原始代码 
  2. if(flag === "unkown"name = "yichuan"
  3.  
  4. //重构代码 
  5. class User
  6.   get name(){ 
  7.     return "yichuan"
  8.   } 

6. 引入断言

在进行程序开发时,只有当某个条件为真时代码才能正常运行,常规做法是使用注释进行解释。而使用断言可以明确标明假设,因为其时一个条件表达式,应当总是恒等于真,断言的失败不应该被系统任何地方捕获。

断言在交流上具有很高的价值,可以解决了当下正在追踪的错误,但是自测代码降低了断言在调试过程中的价值,因为逐步逼近的单元测试通常有助于调试。

原始代码:

  1. func(num){ 
  2.   return (discountRate) ? num - (discountRate * num) : num; 

重构代码:

  1. set discountRate(num){ 
  2.   assert(null === num || num >= 0); 
  3.   discountRate= num;   

小结

在本文中,主要介绍了如何简化条件逻辑,可以对条件逻辑进行操作,而代码也变得更加清晰易懂。

参考文章

《重构──改善既有代码的设计(第2版)》

 

责任编辑:武晓燕 来源: 前端万有引力
相关推荐

2022-04-21 07:20:39

Javascript重构逻辑

2021-07-01 08:28:24

前端搬移特性开发技术

2021-08-03 08:13:48

重构API代码

2021-07-03 12:28:30

前端数据代码

2010-09-03 14:56:12

SQLSELECT语句

2013-09-16 10:57:59

苹果世界

2021-06-05 05:11:52

代码状态机逻辑

2020-06-10 08:37:21

JavaScript重构技巧

2020-12-08 06:20:49

前端重构Vue

2021-06-23 10:32:24

前端ES6代码

2013-04-12 10:17:56

重构业务逻辑

2013-06-09 10:37:14

架构框架

2012-07-27 10:30:12

重构

2022-08-08 13:24:28

整洁架构架构前端

2009-07-22 07:47:00

Scala客户代码

2019-02-18 16:21:47

华为代码重构

2011-08-16 09:47:58

编程

2023-03-10 10:29:19

前端逻辑拆分

2019-04-03 08:10:17

代码架构信息

2022-12-26 00:02:24

重构代码软件
点赞
收藏

51CTO技术栈公众号