【问题标题】:Golang. Refactoring || Pattern || any solution戈朗。重构 ||图案 ||任何解决方案
【发布时间】:2016-06-28 14:30:23
【问题描述】:

问题:有一个表关联键的列表。有必要为每个表实现 CRUD + 对表的细节(分页等)的一些功能。 麻烦:在每个表的每个功能实现中重复了大约 50% 的代码。 问题:语言的细节,优化/重构/使用相似代码模式的方法是什么?

示例代码部分

//------------------------------------------------------------------
//  user
//----------------------------------------------------------------------
func (d *Database) UserCreate(email, password, username string, role int) *Answer {
    //variables
    answer := d.initCall("UserCreate")
    user := new(User)
    //check exist user
    if userExist := d.DB.Find(&User{}, &User{Email:email}).Error; userExist == nil {
        answer.AnswerJSON.ErrorAnswer.Message = "[usercreate] user already exist"
        answer.AnswerJSON.Result = nil
        answer.AnswerJSON.Status = false
    } else {

        userinfo := UserInfo{Data:time.Now()}
        session := Session{Data:time.Now()}
        cook := Cook{}

        //make support  tables object
        //userinfo object
        userinfo.Password = password
        userinfo.Username = username
        //cook object
        cook.SessionID = session.ID
        cook.Cookie = d.cookgeneratenew("somesaltforcooksgenerate")
        cook.Status = true
        cook.Lastconnect = time.Now()
        cook.CountConnect += 1

        //user object
        user.Email = email
        user.Session = session
        user.UserInfo = userinfo
        user.Cook = cook
        user.Role = int64(role)

        //make request + //serizlizations to json answer
        if err := d.DB.Create(user).Error; err != nil {
            answer.AnswerJSON.ErrorAnswer.Message = err.Error()
            answer.AnswerJSON.Status = false
        } else {
            answer.AnswerJSON.Result = user
            answer.AnswerJSON.Status = true
        }
    }
    d.serilize(answer)
    return answer
}
func (d *Database) UserDelete(userid int64) *Answer {
    answer := d.initCall("UserDelete")
    user := new(User)
    //check exists
    if userExists := d.DB.Find(user, "ID = ?", userid).Error; userExists == nil {
        if userDelete := d.DB.Delete(user).Error; userDelete != nil {
            answer.AnswerJSON.ErrorAnswer.Message = userExists.Error()
            answer.AnswerJSON.Status = false
        } else {
            answer.AnswerJSON.Status = true
            answer.AnswerJSON.ErrorAnswer = nil
        }
    } else {
        answer.AnswerJSON.ErrorAnswer.Message = userExists.Error()
        answer.AnswerJSON.Status = false
    }
    d.serilize(answer)
    return answer
}
func (d *Database) UserRead(userid int64) *Answer {
    answer := d.initCall("UserRead")
    user := new(User)
    if userExists := d.DB.Find(user, "ID = ?", userid).Error; userExists != nil {
        answer.AnswerJSON.ErrorAnswer.Message = userExists.Error()
        answer.AnswerJSON.Status = false
    } else {
        if rel := d.DB.Model(user).Related(&user.Session).Error; rel != nil {
            answer.AnswerJSON.Result = nil
            answer.AnswerJSON.ErrorAnswer.Message = rel.Error()
            answer.AnswerJSON.Status = false
        } else if rel = d.DB.Model(user).Related(&user.UserInfo).Error; rel != nil {
            answer.AnswerJSON.Result = nil
            answer.AnswerJSON.ErrorAnswer.Message = rel.Error()
            answer.AnswerJSON.Status = false
        } else if rel = d.DB.Model(user).Related(&user.Cook).Error; rel != nil {
            answer.AnswerJSON.Result = nil
            answer.AnswerJSON.ErrorAnswer.Message = rel.Error()
            answer.AnswerJSON.Status = false
        } else {
            answer.AnswerJSON.Result = user
            answer.AnswerJSON.ErrorAnswer = nil
            answer.AnswerJSON.Status = true
        }
    }
    d.serilize(answer)
    return answer
}
func (d *Database) UserReadAll() *Answer {
    answer := d.initCall("UserReadAll")
    users := []User{}

    if usersGet := d.DB.Find(&users).Error; usersGet != nil {
        answer.AnswerJSON.ErrorAnswer.Message = usersGet.Error()
        answer.AnswerJSON.Status = false
    } else {
        for _, user := range users {
            d.DB.Model(user).Related(&user.Session)
            d.DB.Model(user).Related(&user.UserInfo)
            d.DB.Model(user).Related(&user.Cook)
        }
        answer.AnswerJSON.Result = users
        answer.AnswerJSON.ErrorAnswer = nil
        answer.AnswerJSON.Status = true
    }
    d.serilize(answer)
    return answer
}
func (d *Database) UserUpdate(userid int64, uu *UserUpdateStruct) *Answer {
    answer := d.initCall("UserUpdate")
    user := new(User)

    if userExists := d.DB.Find(user, "ID = ?", userid).Error; userExists != nil {
        answer.AnswerJSON.ErrorAnswer.Message = userExists.Error()
        answer.AnswerJSON.Status = false
    } else {
        //get relevating struct info
        d.DB.Model(user).Related(&user.Session)
        d.DB.Model(user).Related(&user.UserInfo)
        d.DB.Model(user).Related(&user.Cook)

        //update columns
        if uu.Email != "" {
            user.Email = uu.Email
        }
        if uu.Avatar > 0 {
            user.UserInfo.Avatar = uu.Avatar
        }
        if uu.Birthday != "" {
            user.UserInfo.Birthday = uu.Birthday
        }
        if uu.Location != "" {
            user.UserInfo.Location = uu.Location
        }
        if uu.Male != "" {
            user.UserInfo.Male = uu.Male
        }
        if uu.Password != "" {
            user.UserInfo.Password = uu.Password
        }
        if uu.Role > 0 {
            if roleErr := d.DB.Find(&Role{}).Error; roleErr != nil {
                //role not found
                fmt.Printf("[userupdate] role not found `%d`\n", uu.Role)
            } else {
                user.Role = uu.Role
            }
        }

        //update
        if errUpdate := d.DB.Save(user).Error; errUpdate != nil {
            answer.AnswerJSON.ErrorAnswer.Message = errUpdate.Error()
            answer.AnswerJSON.Status = false
        } else {
            answer.AnswerJSON.Result = user
            answer.AnswerJSON.ErrorAnswer = nil
            answer.AnswerJSON.Status = true
        }
    }
    d.serilize(answer)
    return answer
}
func (d *Database) UserPaginate(page, countPage int) *Answer {
    answer := d.initCall("UserPaginate")
    result := []*User{}
    if errPag := d.DB.Limit(countPage).Offset((page * countPage) - countPage).Find(&result).Error; errPag != nil {
        answer.AnswerJSON.ErrorAnswer.Message = errPag.Error()
        answer.AnswerJSON.Status = false
    } else {
        for _, user := range result {
            d.DB.Model(&user).Related(&user.Session)
            d.DB.Model(&user).Related(&user.UserInfo)
            d.DB.Model(&user).Related(&user.Cook)
        }
        answer.AnswerJSON.Result = result
        answer.AnswerJSON.ErrorAnswer = nil
        answer.AnswerJSON.Status = true
    }
    d.serilize(answer)
    return answer
}
//-------------------------------------------------------------------
//  category
//--------------------------------------------------------------------
func (d *Database) CategoryCreate(name string) *Answer {
    //variables
    answer := d.initCall("CategoryCreate")
    cat := new(Category)
    //check exist user
    if catExist := d.DB.Find(&Category{}, &Category{Name:name}).Error; catExist == nil {
        answer.AnswerJSON.ErrorAnswer.Message = "[categorycreate] category already exist"
        answer.AnswerJSON.Result = nil
        answer.AnswerJSON.Status = false
    } else {
        cat.Name = name
        //make request + //serizlizations to json answer
        if err := d.DB.Create(cat).Error; err != nil {
            answer.AnswerJSON.ErrorAnswer.Message = err.Error()
            answer.AnswerJSON.Status = false
        } else {
            answer.AnswerJSON.Result = cat
            answer.AnswerJSON.Status = true
        }
    }
    d.serilize(answer)
    return answer
}
func (d *Database) CategoryDelete(catid int64) *Answer {
    answer := d.initCall("CategoryDelete")
    cat := new(Category)
    //check exists
    if catExists := d.DB.Find(cat, "ID = ?", catid).Error; catExists == nil {
        if catDelete := d.DB.Delete(cat).Error; catDelete != nil {
            answer.AnswerJSON.ErrorAnswer.Message = catExists.Error()
            answer.AnswerJSON.Status = false
        } else {
            answer.AnswerJSON.Status = true
            answer.AnswerJSON.ErrorAnswer = nil
        }
    } else {
        answer.AnswerJSON.ErrorAnswer.Message = catExists.Error()
        answer.AnswerJSON.Status = false
    }
    d.serilize(answer)
    return answer
}
func (d *Database) CategoryRead(catid int64) *Answer {
    answer := d.initCall("CategoryRead")
    cat := new(Category)
    if catExists := d.DB.Find(cat, "ID = ?", catid).Error; catExists != nil {
        answer.AnswerJSON.ErrorAnswer.Message = catExists.Error()
        answer.AnswerJSON.Status = false
    } else {
        if rel := d.DB.Model(cat).Related(&cat.Post).Error; rel != nil {
            answer.AnswerJSON.Result = nil
            answer.AnswerJSON.ErrorAnswer.Message = rel.Error()
            answer.AnswerJSON.Status = false
        } else {
            for x, p := range cat.Post {
                d.DB.Model(&p).Related(&p.Comment)
                d.DB.Model(&p).Related(&p.PostSeo)
                cat.Post[x] = p
            }
            answer.AnswerJSON.Result = cat
            answer.AnswerJSON.ErrorAnswer = nil
            answer.AnswerJSON.Status = true
        }
    }
    d.serilize(answer)
    return answer
}
func (d *Database) CategoryReadAll() *Answer {
    answer := d.initCall("CategoryReadAll")
    cats := []Category{}

    if catsGet := d.DB.Find(&cats).Error; catsGet != nil {
        answer.AnswerJSON.ErrorAnswer.Message = catsGet.Error()
        answer.AnswerJSON.Status = false
    } else {
        //categorys
        for _, cat := range cats {
            d.DB.Model(cat).Related(&cat.Post)
            //get relete POST
            for x, p := range cat.Post {
                d.DB.Model(&p).Related(&p.Comment)
                d.DB.Model(&p).Related(&p.PostSeo)
                cat.Post[x] = p
            }
        }
        answer.AnswerJSON.Result = cats
        answer.AnswerJSON.ErrorAnswer = nil
        answer.AnswerJSON.Status = true
    }
    d.serilize(answer)
    return answer
}
func (d *Database) CategoryUpdate(catid int64, name string) *Answer {
    answer := d.initCall("CategoryUpdate")
    cat := new(Category)

    if catExists := d.DB.Find(cat, "ID = ?", catid).Error; catExists != nil {
        answer.AnswerJSON.ErrorAnswer.Message = catExists.Error()
        answer.AnswerJSON.Status = false
    } else {
        //get relevating struct info
        d.DB.Model(cat).Related(&cat.Post)

        //update columns
        if name != "" {
            cat.Name = name
        }
        //update
        if errUpdate := d.DB.Save(cat).Error; errUpdate != nil {
            answer.AnswerJSON.ErrorAnswer.Message = errUpdate.Error()
            answer.AnswerJSON.Status = false
        } else {
            answer.AnswerJSON.Result = cat
            answer.AnswerJSON.ErrorAnswer = nil
            answer.AnswerJSON.Status = true
        }
    }
    d.serilize(answer)
    return answer
}
func (d *Database) CategoryPaginate(page, countPage int) *Answer {
    answer := d.initCall("CategoryPaginate")
    result := []*Category{}
    if errPag := d.DB.Limit(countPage).Offset((page * countPage) - countPage).Find(&result).Error; errPag != nil {
        answer.AnswerJSON.ErrorAnswer.Message = errPag.Error()
        answer.AnswerJSON.Status = false
    } else {
        for _, cat := range result {
            d.DB.Model(&cat).Related(&cat.Post)
            //get relete POST
            for x, p := range cat.Post {
                d.DB.Model(&p).Related(&p.Comment)
                d.DB.Model(&p).Related(&p.PostSeo)
                cat.Post[x] = p
            }
        }
        answer.AnswerJSON.Result = result
        answer.AnswerJSON.ErrorAnswer = nil
        answer.AnswerJSON.Status = true
    }
    d.serilize(answer)
    return answer
}

【问题讨论】:

    标签: go


    【解决方案1】:

    我可以看到您的代码中有很多冗余。几个月前我遇到了同样的问题并且有很好的答案。看看这里:How to return dynamic type struct in Golang?

    基本上你会拥有同样的三个函数(add/edit/delete/count)(我不知道你用的是什么db,我用的是NoSql Rethinkdb,但原理是一样的):

    func (c Main) Get(modelname string) interface{} {
    
       //your query here for getting stuff from model name and return interface
    
       rows, err := rethink.Table(modelname).OrderBy(rethink.Asc("sortNo")).Run(c.DB)
       if err != nil {
           log.Println(err)
           return nil
       }
    
       if (modelType == "brand") {
    
           var brands  []*models.Brand
           rows.All(&brands)
    
           return brands
    
       }
       //rest of your models here or use some switch
    })
    

    我通常将所有与数据库相关的函数放在一些帮助程序中(这主要是因为测试)。

    我认为这是很好的方向,因为这样您的代码易于维护,并且您将只更改辅助函数,而不是为每个模型执行添加/删除/更新的数百万个虚构。

    【讨论】:

    • +1 我喜欢他脑海中的概念,他无法具体说明。你已经为这个想法提供了一个完美的形式。谢谢。
    • 这也是一个相对常见的习惯用法,通过引用将目标作为接口参数传递给函数,类似于io.Read()sql.Scan()。如果您的Get() 函数接受一个必须是指针的参数dest interface{},它可以将dest 直接传递给您的rows.All()(或基sql.Scan(),或sqlx.Get() 等),而无需知道它是什么类型,并且不必在Get() 中为每个域模型类型提供特定的代码块。
    【解决方案2】:

    我在代码中实现了这个想法。结果很好。

    重构代码

    //------------------------------------------------------------------------
    //  REFACTORING
    //-----------------------------------------------------------------------
    func (d *Database)Create(model string, params interface{}) *Answer {
        //variables
        answer := d.initCall("Create")
        tableType := d.Mapper[model]
        var (
            errorExists interface{}
            flag bool
        )
    
        //logic switch types
        switch tableType.(type) {
        case User:
            params := params.(UserUpdate)
            if errorExists = d.DB.Find(&User{}, &User{Email:params.Email}).Error; errorExists == nil {
                flag = false
            } else {
                flag = true
                //variables
                user := new(User)
                userinfo := UserInfo{Data:time.Now()}
                session := Session{Data:time.Now()}
                cook := Cook{}
    
                //make support  tables object
                //userinfo object
                userinfo.Password = params.Password
                userinfo.Username = params.Username
                //cook object
                cook.SessionID = session.ID
                cook.Cookie = d.cookgeneratenew("somesaltforcooksgenerate")
                cook.Status = true
                cook.Lastconnect = time.Now()
                cook.CountConnect += 1
    
                //user object
                user.Email = params.Email
                user.Session = session
                user.UserInfo = userinfo
                user.Cook = cook
                user.Role = int64(params.Role)
    
                //assign ready model for create
                tableType = user
            }
    
        case Category:
            params := params.(CategoryUpdate)
            if errorExists = d.DB.Find(&Category{}, &Category{Name:params.Name}).Error; errorExists == nil {
                //set logic switcher
                flag = false
            } else {
                //set logic switcher
                flag = true
    
                //speciffic functional
                cat := new(Category)
                cat.Name = params.Name
    
                //assign ready model for create
                tableType = cat
        }
        default:
            fmt.Printf("Wrong type table\n")
        }
    
        //call function create model
        if flag {
            if err := d.DB.Create(tableType).Error; err != nil {
                answer.AnswerJSON.ErrorAnswer.Message = err.Error()
                answer.AnswerJSON.Status = false
            } else {
                answer.AnswerJSON.Result = tableType
                answer.AnswerJSON.Status = true
            }
        } else {
            answer.AnswerJSON.ErrorAnswer.Message = "object already exist"
            answer.AnswerJSON.Result = nil
            answer.AnswerJSON.Status = false
        }
        //make answer
        d.serilize(answer)
        return answer
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-25
      • 1970-01-01
      • 2011-12-24
      • 2011-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-30
      相关资源
      最近更新 更多