猿问

避免反射 - 如何最好地重构此代码?

我开始尝试使用 Go,到目前为止,它一直是一个爆炸。我决定做一个小应用程序来帮助朋友在他的(小)公司组织信息业务相关的信息,我想我会用Go来实现它。


我还没有(完全)遇到问题,更多的是一个问题,我什么时候应该考虑使用反射?例如,我有 3 个相关类型:Company,Project和Staff. 它们都有几个共同的字段(例如id, name),因此您可以想象,从数据库(我正在使用MySQL)加载它们的函数都非常相似。


看LoadCompany(), LoadStaff(), 和LoadProject():


// Loads the company from the database with the given id.

func LoadCompany(id int) (Company, error) {

    db := tools.OpenDB()

    defer db.Close()

    stmt, err := db.Prepare("SELECT * FROM companies WHERE id = ?")

    if err != nil {

        log.Panic(err)

    }   

    var c Company 

    err = stmt.QueryRow(id).Scan(&c.id, &c.FullName, &c.Name, &c.History, &c.Overview, &c.Est, &c.Phone, &c.Website, &c.Email)

    if err != nil {

        return Company{}, err 

    }   

    return c, nil 

}


// Loads the staff from the database with the given id.

func LoadStaff(id int) (Staff, error) {

    db := tools.OpenDB()

    defer db.Close()

    stmt, err := db.Prepare("SELECT * FROM staff WHERE id = ?")

    if err != nil {

        log.Panic(err)

    }

    var s Staff

    err = stmt.QueryRow(id).Scan(&s.id, &s.FullName, &s.Name, &s.Email, &s.Joined, &s.Left, &s.History, &s.Phone, &s.Position)

    if err != nil {

        return Staff{}, err

    }

    return s, nil

}


// Loads the project from the database with the given id.

func LoadProject(id int) (Project, error) {

    db := tools.OpenDB()

    defer db.Close()

    stmt, err := db.Prepare("SELECT * FROM projects WHERE id = ?")

    if err != nil {

        log.Panic(err)

    }

    var p Project

    err = stmt.QueryRow(id).Scan(&p.id, &p.Title, &p.Overview, &p.Value, &p.Started, &p.Finished, &p.Client, &p.Architect, &p.Status)

    if err != nil {

        return Project{}, err

    }

    return p, nil

}

当我写的时候LoadCompany(),我对自己感觉很好(嗯,作为一个初学者/中级程序员)因为它看起来很小很干净。但是当我写LoadStaff()和的时候LoadProject(),我所做的只是复制和调整。我确信有更好的方法可以做到这一点,但是在阅读了Pike 的帖子后,我已经厌倦了进行反思:


[反射是]一种强大的工具,除非绝对必要,否则应谨慎使用并避免使用。


所以我的问题是,我应该使用反射吗,如果是这样,你能给我一些关于最好的技术的建议吗?这只是冰山一角,因为我觉得与这些类型相关的其余函数和方法似乎都是类似的重复(不要让我开始测试!)。


大话西游666
浏览 146回答 1
1回答

呼唤远方

就像是:func LoadObject(sql string, id int, dest ...interface{}) error {    db := tools.OpenDB()    defer db.Close()    stmt, err := db.Prepare(sql)    if err != nil {        log.Panic(err)    }       defer stmt.Close()    return stmt.QueryRow(id).Scan(dest)}// Loads the company from the database with the given id.func LoadCompany(id int) (c Company, err error) {    err = LoadObject("SELECT * FROM companies WHERE id = ?", &c.id,        &c.FullName, &c.Name, &c.History, &c.Overview, &c.Est, &c.Phone, &c.Website, &c.Email)    return}请注意,我还没有编译此代码,但希望它足以给您一个想法。几点建议:通读文档:https : //golang.org/pkg/database/sql/sql.DB在程序启动时创建实例在 SQL 语句中显式指定列顺序 ( select full_name, history, .... from companies ....)
随时随地看视频慕课网APP

相关分类

Go
我要回答