【问题标题】:What is the best way to have dependency injection in Golang在 Golang 中进行依赖注入的最佳方法是什么
【发布时间】:2018-02-18 21:08:08
【问题描述】:

我是 Golang 的初学者,我正在开发一个小型库,该库需要在代码中的某个位置获取数据库连接以进行不同的子包/方法调用。我只是想知道我该如何管理这个?

例如,如果我设法拥有一个网络服务器,它可以与处理程序一起使用,那么我怎样才能在这个函数中获得这个连接? 它可以与另一个进程、简单的方法调用或 MVC 模型一起使用吗?

我不想使用 global,因为对我来说这是一种不好的做法,除非它是非常特殊的方式(或以某种方式棘手)。

我在不同的网站上阅读了很多文章,但我仍然在询问和学习不同的意见和经验。

感谢您的宝贵时间!

【问题讨论】:

  • 那里有很多不错的软件包。但是工厂方法的简单映射也可以(在很多情况下,但不是全部)。
  • 一个库、框架,甚至工厂地图几乎可以肯定是不必要的过度复杂化。依赖注入只是意味着如果 Foo 需要一个 Bar,Foo 不创建 Bar,Foo 从任何创建/调用 Foo 的对象接收 Bar。
  • @KavehShahbazian 是的,我尝试使用 map[string]interface{} 实现一个简单的接口,但我认为我需要更多练习才能了解一些要求,例如注入器/类型..
  • @Adrian 我同意你的观点 :) 但是找到一个注入它们的好方法/过程会很好。现在我找到了一种方法,比如创建一个上下文,将我的实例存储在里面,然后将这个上下文提供给我需要它的结构,但我真的不喜欢这个
  • 根据我的卑微经验,context.Context.Value() (充其量)是一种疾病。应该避免它。 (恕我直言)context.Context 是实现取消层次结构的最佳方式(结合sync.WaitGroup 进行确认)。 context.Context 本质上是不可变的,这是一件好事。值部分实际上应该只在请求范围内使用(我也从未将它用于此目的)。

标签: go dependency-injection


【解决方案1】:

创建一个代表资源的结构体​,让我们调用 Cart.向该结构添加 get 和 post 方法。这些方法应该是 http 处理程序。在 main 中创建一个带有 db 接口的结构实例。并在路线中调用 Cart.get。现在在 get 方法中,您可以访问 db 接口。

不是一个工作示例,只是为了了解注入测试的想法。

type storage interface {
    PrepareContext(context.Context, string) (*sql.Stmt, error)
}

func main() {
    db, _ := sql.Open("mysql", `queryString`)
    http.HandleFunc("/", Cart{db}.get)
    http.ListenAndServe(":8080", nil)
}

type Cart struct {
    storage
}

func (crt Cart) get(w http.ResponseWriter, r *http.Request) {
    q, _ := crt.PrepareContext(context.Background(), `select *`)
    fmt.Println(q.Exec())
}

/////////Test
type testDB struct{}

func (c testDB) PrepareContext(context.Context, string) (*sql.Stmt, error) {
    return nil, nil
}
func TestGet(t *testing.T) {
    db := testDB{}
    _ = Cart{db}

    //http test here
}

【讨论】:

  • 感谢您的回答,我仍然从不使用“上下文”,所以即使有文档和示例,我现在也感到迷茫。我也读过这个,它说不要滥用上下文来存储价值在里面,medium.com/@cep21/…,但由于我不习惯,我想我现在会使用一种简单的方法,我会继续练习这种语言:)
  • 应该是crt.storage.PrepareContext,而不是crt.PrepareContext
【解决方案2】:

我建议Dargo 是Java CDI 和/或JSR-330 风格的注入引擎。它使用结构注释,并使用反射或使用创建者函数执行注入。它支持不同的服务生命周期,包括 Singleton(仅创建一次,惰性)、PerLookup(每次注入或查找时创建)、Immediate(仅创建一次,急切地创建)和 DargoContext(与 context.Context 的生命周期相关联)

【讨论】:

    【解决方案3】:

    您也可以尝试Hiboot,这是一个支持开箱即用的依赖注入的 web/cli 应用程序框架。

    Docs

    // HelloService is a simple service interface, with interface, we can mock a fake service in unit test
    type HelloService interface {
        SayHello(name string) string
    }
    
    type helloServiceImpl struct {
    }
    
    func init() {
        // Register Rest Controller through constructor newHelloController
        // Register Service through constructor newHelloService
        app.Register(newHelloController, newHelloService)
    }
    
    // please note that the return type name of the constructor HelloService,
    // hiboot will instantiate a instance named helloService for dependency injection
    func newHelloService() HelloService {
        return &helloServiceImpl{}
    }
    
    // SayHello is a service method implementation
    func (s *helloServiceImpl) SayHello(name string) string {
        return "Hello" + name
    }
    
    // PATH: /login
    type helloController struct {
        web.Controller
        helloService HelloService
    }
    
    // newHelloController inject helloService through the argument helloService HelloService on constructor
    func newHelloController(helloService HelloService) *helloController {
        return &helloController{
            helloService: helloService,
        }
    }
    
    // Get /
    // The first word of method name is the http method GET
    func (c *helloController) Get(name string) string {
        return c.helloService.SayHello(name)
    }
    

    【讨论】:

      【解决方案4】:

      我建议尝试https://github.com/facebookgo/inject。它允许定义对象图并使用结构注释指定依赖关系。使用反射执行注入。

      【讨论】:

      • 谢谢,去看看这个:)
      【解决方案5】:

      对于 IoC 容器,你可以试试这个包: https://github.com/golobby/container

      单例绑定示例:

      container.Singleton(func() Database {
        return &MySQL{}
      })
      

      解析示例:

      var db Database
      container.Make(&db)
      

      如您所见,使用起来非常简单。

      【讨论】:

        猜你喜欢
        • 2018-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-14
        相关资源
        最近更新 更多