函数封装的一个案例
最近在写 webhook-go 项目,在处理 webhook 请求的时候,我写了一段这样的代码:
go
// 处理Gitee blog 仓库的 Webhook请求
// 参数:c 请求上下文
func Blog(c *gin.Context) {
// 验证 webhook 请求
status, err := validateRequest(c)
// do something
}
// validateRequest 验证 Gitee 请求的合法性。
// 参数:c 请求上下文
func validateRequest(c *gin.Context) (int, error) {
// 获取请求头中的token和timestamp
token := c.GetHeader("X-Gitee-Token")
timestamp := c.GetHeader("X-Gitee-Timestamp")
// 验证token和timestamp的合法性
return validateParams(token, timestamp)
}
// 验证参数
func validateParams(token, timestamp string) (int, error) {
// do something
}这里为什么不把
go
// 获取请求头中的token和timestamp
token := c.GetHeader("X-Gitee-Token")
timestamp := c.GetHeader("X-Gitee-Timestamp")放在 validateParams 函数中呢?因为 validateParams 函数是验证参数的合法性,而不是获取参数。
validateRequest 函数的功能是验证请求的合法性,之后可能会扩展其它功能,比如验证 ip ,如果直接在 Blog 函数中调用 validateParams ,那就需要在 Blog 函数中添加验证 ip 的逻辑。这样显然是违法了开闭原则。
从这里,我们就可以看出了代码封装的基本逻辑,首先是明确函数的功能,然后,在函数里面明确步骤,最后按照步骤来实现。其中,在明确函数功能这一步,我们要做到有预见性,能够考虑到未来的变化,当然,也不宜过度设计。