16

如何优雅的写校验函数

 4 years ago
source link: https://studygolang.com/articles/29319
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

有的时候,为了检查入参,会有很多项需要检查,如果一个一个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 < 0 || id > 1000000 {
            return false
        }
    }

    if c.rulelevel != "" {
        level, err := strconv.Atoi(c.rulelevel)
        if err != nil {
            return false
        }

        //level range 0-16
        if level < 0 || 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 < 0 || 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 < 0 || 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知识

FveQFjN.jpg!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK