如何优雅的写校验函数
2012 年 10 月 2 日
有的时候,为了检查入参,会有很多项需要检查,如果一个一个if-else的去判断,会显得很low,先看一个比较丑的写法:
func checkQeuryParam(c *condition) bool { if c.offset > 100000 { return false } if c.limit > 100 { return false } if c.timebegin != "" { zone := time.FixedZone("CST", 8*3600) t, err := time.ParseInLocation("2006-01-02T15:04:05.000+0800", c.timebegin, zone) if err != nil { aialog.Error.Printf("Query time %s is invalid.\n", c.timebegin) return false } c.timebegin = t.Format("2006-01-02T15:04:05.000+0800") } //ip no check //come_from no check //event if c.event != "" { if c.event != "added" && c.event != "modified" && c.event != "deleted" { return false } } //ruleid if c.ruleid != "" { id, err := strconv.Atoi(c.ruleid) if err != nil { return false } //id range, temporary if id 1000000 { return false } } if c.rulelevel != "" { level, err := strconv.Atoi(c.rulelevel) if err != nil { return false } //level range 0-16 if level 15 { return false } } if c.agentid != "" { if len(c.agentid) > 64 { return false } } //order if c.order != "" { if c.order != "desc" && c.order != "asc" { return false } } return true }
1、易读性很差
2、修改麻烦
3、不易扩展
4、打印失败信息麻烦,需要每个异常分支添加
调整为如下方式:
func (c *condition)checkOffset() bool { if c.offset > 100000 { return false } return true } func (c *condition)checkLimit() bool { if c.limit > 100 { return false } return true } func (c *condition)checkTime() bool { if c.timebegin != "" { zone := time.FixedZone("CST", 8*3600) t, err := time.ParseInLocation("2006-01-02T15:04:05.000+0800", c.timebegin, zone) if err != nil { aialog.Error.Printf("Query time %s is invalid.\n", c.timebegin) return false } c.timebegin = t.Format("2006-01-02T15:04:05.000+0800") } return true } func (c *condition)checkEvent() bool { if c.event != "" { if c.event != "added" && c.event != "modified" && c.event != "deleted" { return false } } return true } func (c *condition)checkRuleid() bool { if c.ruleid != "" { id, err := strconv.Atoi(c.ruleid) if err != nil { return false } //id range, temporary if id 1000000 { return false } } return true } func (c *condition)checkRulelevel() bool { if c.rulelevel != "" { level, err := strconv.Atoi(c.rulelevel) if err != nil { return false } //level range 0-16 if level 15 { return false } } return true } func (c *condition)checkAgentid() bool { if c.agentid != "" { if len(c.agentid) > 64 { return false } } return true } func (c *condition)checkOrder() bool { if c.order != "" { if c.order != "desc" && c.order != "asc" { return false } } return true } func checkQeuryParam(c *condition) bool { checks := []struct{ name string fn func() bool }{ {"check offset", c.checkOffset}, {"check limit", c.checkLimit}, {"check time", c.checkTime}, {"check event", c.checkEvent}, {"check rule id", c.checkRuleid}, {"check rule level", c.checkRulelevel}, {"check agent id", c.checkAgentid}, {"check order", c.checkOrder}, } for _, check := range checks { if !check.fn() { aialog.Error.Printf("%s failed.\n", check.name) return false } } return true }
1、条理清晰,易读性好
2、增加判断时,直接新增函数
3、打印失败信息也比较方便,且新增判断也不用新增打印
注:
对于函数名作为参数时,如果是传的方法,需要连对象一起传入。
如上的fn,传入时为c.checkXXX,c为这个方法的实际调用对象。
欢迎关注我们的微信公众号,每天学习Go知识