如何優雅的寫校驗函數

有的時候,爲了檢查入參,會有不少項須要檢查,若是一個一個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
}

一、易讀性不好
二、修改麻煩
三、不易擴展
四、打印失敗信息麻煩,須要每一個異常分支添加code

調整爲以下方式:orm

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
}

一、條理清晰,易讀性好
二、增長判斷時,直接新增函數
三、打印失敗信息也比較方便,且新增判斷也不用新增打印對象

注:
對於函數名做爲參數時,若是是傳的方法,須要連對象一塊兒傳入。
如上的fn,傳入時爲c.checkXXX,c爲這個方法的實際調用對象。ip

相關文章
相關標籤/搜索