0x00 前言
在日常编写代码时常会遇到多条件判断情况,在我们的编写过程中常会使用if-else或switch来进行校验,但这种情况会导致代码可读性降低,本文将使用表驱动的方式进行if-else的代码块重写
0x01 原理
将所需要的判断调节通过一张hash表进行注册,使用时只需要对hash表进行查询即可,降低了代码量的同时增加可读性。
0x02 代码
需求:针对一条URL,对不同的请求进行不同的响应。
历史代码:
代码结构为
D:.
│ go.mod
│ go.sum
│ main.go
│
├─handler
│ main_handler.go
│ table_driver_handler.go
│
└─register
register.go
常规写法 main_handler.go
func MainHandler(c *gin.Context) {
method := c.Request.Method
if method == "GET" {
c.JSON(http.StatusOK, gin.H{
"message": "GET Request",
})
} else if method == "POST" {
c.JSON(http.StatusOK, gin.H{
"message": "POST Request",
})
} else if method == "DELETE" {
c.JSON(http.StatusOK, gin.H{
"message": "DELETE Request",
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"message": "No Such Function",
})
}
return
}
使用表驱动时
注册代码 register.go
package register
// 注册表
var (
Res = make(map[string]string)
)
// 添加内容
func putMap(method, res string) {
Res[method] = res
}
// 注册内容
func registerRequest(res map[string]string) {
putMap("GET", "GET Request")
putMap("POST", "POST Request")
putMap("DELETE", "DELETE Request")
}
// Go在初始化项目时会读取项目中所有init提前编译
func init() {
registerRequest(Res)
}
运行时的注册效果
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
register.Res: map[DELETE:DELETE Request GET:GET Request POST:POST Request]
处理代码 table_driver_handler.go
package handler
import (
"net/http"
"tableDriver/register"
"github.com/gin-gonic/gin"
)
func TableHandler(c *gin.Context) {
method := c.Request.Method
if register.Res[method] != "" {
c.JSON(http.StatusBadRequest, gin.H{
"message": "No Such Function",
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"message": register.Res[method],
})
}
return
}
主函数
package main
import (
"fmt"
"tableDriver/handler"
"tableDriver/register"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
r.Use(gin.Logger(), gin.Recovery())
gin.SetMode(gin.DebugMode)
fmt.Printf("register.Res: %v\n", register.Res)
r.Any("/api/common/v1", handler.MainHandler)
r.Any("/api/table-driver/v1", handler.MainHandler)
r.Run("0.0.0.0:30999")
}
0x03 分析
可以发现,常规写法代码由四个判断条件组成,可读性较差且拓展时需要在后续添加if判断语句,拓展性差。
而使用表驱动写法代码可读性提升,并且易于扩展。
0x04 总结
综上所述,使用表驱动可以有效的提升代码的可读性与扩展性,在遇到多条件判断的情况时可以采用该方法,但要注意返回结果需要通用,否则不宜采用。
0x05 附录
上文所述是只定义了返回数据的表驱动,同样我们可以定义函数来作为表的value值,示例如下。
register/register.go
package register
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 设置 funHandler 为带参数 gin.Context 的函数类
type funHandler func(*gin.Context)
// FunMap 注册表
var FunMap = make(map[string]funHandler)
// Go在初始化项目时会读取项目中所有init提前编译,即初始化注册表
func init() {
FunMap["GET"] = func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "GET Request",
})
}
FunMap["POST"] = func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "POST Request",
})
}
FunMap["DELETE"] = func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "DELETE Request",
})
}
}
TableHandler如下所示
package handler
import (
"github.com/gin-gonic/gin"
"net/http"
"tableDriver/register"
)
// TableHandler 表驱动handler
func TableHandler(c *gin.Context) {
method := c.Request.Method
funHandler, ok := register.FunMap[method]
if !ok {
c.JSON(http.StatusOK, gin.H{
"message": "No Such Function",
})
return
}
funHandler(c)
}