代码地址: https://gitee.com/lymgoforIT/golang-trick/tree/master/16-avoid-multi-if
一:简介
相信大家在工作中都见过这么一条规范:如果你需要三层的嵌套,说明你的程序已经开始混乱,应该修复你的程序。
如下代码:(为了演示,故意没有使用&&
运算)
// 职位
type JobPosition struct {
salary int64 // 薪资
name string // 职位名称
workingHours string // 工作时长
}
func (j JobPosition) apply() {
}
// 申请一个合适的职位
func applyForSuitablePosition(positions []JobPosition) {
for _, position := range positions {
if position.salary > 1000 {
if position.name == "super Engineer" {
if position.workingHours == "996" {
position.apply()
}
}
}
}
}
二:表驱动法
凡是可以通过逻辑语句来选择的事物,我们都可以通过查表法来解决,对于简单的情况,当然逻辑语句更为简单、直白,但是随着选项的越来越多,表驱动法就显得更易维护了。
分支代码如下:
func choose1(subtitle string) {
switch subtitle {
case "表驱动法":
fmt.Println("分支一")
case "提早返回":
fmt.Println("分支二")
case "状态模式":
fmt.Println("分支三")
case "空置判断":
fmt.Println("分支四")
}
}
表驱动法代码如下:
var subtitleMap = map[string]string{
"表驱动法":"分支一",
"提早返回":"分支二",
"状态模式":"分支三",
"空置判断":"分支四",
}
func choose2(subtitle string){
if val,ok := subtitleMap[subtitle];ok {
fmt.Println(val)
}
}
可以看到,choose
方法很清晰整洁了,实际工作中map
的val
一般是对象或者func
,此时其实就是工厂模式+策略模式
的使用形式了。
三:快乐路径
快乐路径也即提早返回,一般用于参数校验或者错误处理等场景。
如下:
goodCase
//伪代码段1:
func doSomething() error {
if errorCondition1 {
// some error logic
... ...
return err1
}
// some success logic
... ...
if errorCondition2 {
// some error logic
... ...
return err2
}
// some success logic
... ...
return nil
}
我们看到单分支控制结构的伪代码段 1
有这几个特点:
- 没有使用 else 分支,失败就立即返回;
- “成功”逻辑始终“居左”并延续到函数结尾,没有被嵌入到 if 的布尔表达式为 true 的代码分支中;
- 整个代码段布局扁平,没有深度的缩进;
- 代码的可读性很高
badCase
// 伪代码段2:
func doSomething() error {
if successCondition1 {
// some success logic
... ...
if successCondition2 {
// some success logic
... ...
return nil
} else {
// some error logic
... ...
return err2
}
} else {
// some error logic
... ...
return err1
}
}
伪代码段 2
实现了同样逻辑码段 1
,就使用了带有嵌套的二分支结构,它的特点如下:
- 整个代码段呈现为“锯齿状”,有深度缩进;
- “成功”逻辑被嵌入到
if
的布尔表达式为true
的代码分支中;
很明显,伪代码段 1
的逻辑更容易理解,也更简洁。Go
社区把这种 if
语句的使用方式称为 if
语句的“快乐路径(Happy Path)
”原则,所谓“快乐路径”也就是成功逻辑的代码执行路径,它的特点是这样的:
-
仅使用单分支控制结构;
-
当布尔表达式求值为
false
时,也就是出现错误时,在单分支中快速返回; -
正常逻辑在代码布局上始终“靠左”,这样读者可以从上到下一眼看到该函数正常逻辑的全貌;
-
函数执行到最后一行代表一种成功状态。
Go
社区推荐 Gopher
们在使用 if
语句时尽量符合这些原则,如果你的函数实现代码不符合“快乐路径”原则,你可以按下面步骤进行重构:
-
尝试将“正常逻辑”提取出来,放到“快乐路径”中;
-
如果无法做到上一点,很可能是函数内的逻辑过于复杂,可以将深度缩进到
else
分支中的代码析出到一个函数中,再对原函数实施“快乐路径”原则。
四:状态模式
状态模式即之前一些博客介绍的,一般用于审批流,状态流转等场景。