避免反思 - 我如何才能最好地重构此代码?

时间:2015-12-22 07:49:38

标签: reflection go refactoring

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

我没有(确切地)遇到问题,这更像是一个问题,我应该何时考虑使用反射?例如,我有3种相关类型:CompanyProjectStaff。它们都有几个共同的字段(例如idname),所以你可以想象,从数据库中加载它们的函数(我正在使用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()时,我对自己感觉非常好( ahem 作为初学者/中级程序员),因为它看起来很简洁。但是当我写LoadStaff()LoadProject()时,我所做的只是复制和调整。我确信有更好的方法可以做到这一点,但在阅读Pike's post on it之后,我厌倦了跳入反思:

  <反思是一种强有力的工具,除非有必要,否则应谨慎使用并避免使用。

所以我的问题是,我应该使用反射,如果是这样,你能给我一些关于最佳技术的指针吗?这只是冰山一角,因为我觉得与这些类型相关的其他功能和方法都是同样重复的(并且不要让我开始测试!)。

谢谢!

1 个答案:

答案 0 :(得分:2)

类似的东西:

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 ....
  • 中明确指定列顺序