golang中是否有更好的依赖注入模式?

Jus*_*mas 11 interface go

鉴于此代码:

package main

import (
    "fmt"
)

type datstr string

type Guy interface {
   SomeDumbGuy() string
}

func (d *datstr) SomeDumbGuy() string {
  return "some guy"
}

func someConsumer(g Guy) {
  fmt.Println("Hello, " + g.SomeDumbGuy())
}

func main() {
    var d datstr
    someConsumer(&d)
}
Run Code Online (Sandbox Code Playgroud)

是一个组件接线在一起在完成主接线的依赖一起以正确的方式?好像我在代码中使用了这一点.是否有比这更好的共同模式,还是我在思考它?

Zee*_*han 29

最佳实践是不使用 DI 库。Go 旨在成为一种易于遵循的简单语言。DI 库/框架会将其抽象化(并在某种程度上使 DI 变得神奇)。

  • “最佳实践是不要使用 DI 库。” 这是不是有点太过分了? (14认同)
  • 谁说的?我见过很多使用某种 DI 的优秀项目。谷歌及其 Wire 也会对你的说法提出异议...... (13认同)
  • 不幸的是,我没有使用过wire,也不是Golang DI 方面的专家。然而,我坚信不需要特定的模式,因为任何库都会使程序流程复杂化,而 Golang 的目标是成为一种没有任何*魔法*并且易于遵循的语言。 (4认同)
  • 如果这被列为最佳实践,请添加对此效果的 Go 文档引用。考虑到 Google 创建了 Wire 作为 DI 系统,可以避免反射并保持调用清晰度,我发现这个答案更有可能是不正确的。 (3认同)
  • Go 允许你创建执行 DI 的库。在某种程度上需要抽象。只要遵循 DRY 和 KISS 原则即可。不存在不使用 XYZ 库的最佳实践。除非你的团队滥用了它。恕我直言。 (3认同)
  • 仍然不知道为什么选择这个答案。它混合了两种不同的东西:语言规范和编程模式。本质上,它并没有回答最初的问题,而只是作者的观点。 (3认同)
  • 没有 Go Doc 参考;让自己读了一堆文章并有效地进行。与使用在幕后进行反射或魔法的 DI 框架相比,不使用 DI 框架是更惯用的 Go 语言。 (2认同)
  • 来自企业编程世界的任何人都不会认为不应该使用 DI。这绝对不是最佳实践,相反这是无法维护的。任何具有超过 5 个文件的严肃服务器项目都会导致手动编写接线代码。使用像 Google Wire 这样的东西会让事情变得更容易。简单的语言不应该以坚持程序员的新手水平为目标。 (2认同)

Wil*_*Yeh 10

谷歌的Wire看起来很有希望。有一些关于它的文章:


Wil*_*ert 7

是的,facebookgo注入库允许您接收注入的成员并为您连接图表.

代码:https://github.com/facebookgo/inject

文档:https://godoc.org/github.com/facebookgo/inject

这是文档中的代码示例:

package main

import (
    "fmt"
    "net/http"
    "os"

    "github.com/facebookgo/inject"
)

// Our Awesome Application renders a message using two APIs in our fake
// world.
type HomePlanetRenderApp struct {
    // The tags below indicate to the inject library that these fields are
    // eligible for injection. They do not specify any options, and will
    // result in a singleton instance created for each of the APIs.

    NameAPI   *NameAPI   `inject:""`
    PlanetAPI *PlanetAPI `inject:""`
}

func (a *HomePlanetRenderApp) Render(id uint64) string {
    return fmt.Sprintf(
        "%s is from the planet %s.",
        a.NameAPI.Name(id),
        a.PlanetAPI.Planet(id),
    )
}

// Our fake Name API.
type NameAPI struct {
    // Here and below in PlanetAPI we add the tag to an interface value.
    // This value cannot automatically be created (by definition) and
    // hence must be explicitly provided to the graph.

    HTTPTransport http.RoundTripper `inject:""`
}

func (n *NameAPI) Name(id uint64) string {
    // in the real world we would use f.HTTPTransport and fetch the name
    return "Spock"
}

// Our fake Planet API.
type PlanetAPI struct {
    HTTPTransport http.RoundTripper `inject:""`
}

func (p *PlanetAPI) Planet(id uint64) string {
    // in the real world we would use f.HTTPTransport and fetch the planet
    return "Vulcan"
}

func main() {
    // Typically an application will have exactly one object graph, and
    // you will create it and use it within a main function:
    var g inject.Graph

    // We provide our graph two "seed" objects, one our empty
    // HomePlanetRenderApp instance which we're hoping to get filled out,
    // and second our DefaultTransport to satisfy our HTTPTransport
    // dependency. We have to provide the DefaultTransport because the
    // dependency is defined in terms of the http.RoundTripper interface,
    // and since it is an interface the library cannot create an instance
    // for it. Instead it will use the given DefaultTransport to satisfy
    // the dependency since it implements the interface:
    var a HomePlanetRenderApp
    err := g.Provide(
        &inject.Object{Value: &a},
        &inject.Object{Value: http.DefaultTransport},
    )
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    // Here the Populate call is creating instances of NameAPI &
    // PlanetAPI, and setting the HTTPTransport on both to the
    // http.DefaultTransport provided above:
    if err := g.Populate(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    // There is a shorthand API for the simple case which combines the
    // three calls above is available as inject.Populate:
    //
    //   inject.Populate(&a, http.DefaultTransport)
    //
    // The above API shows the underlying API which also allows the use of
    // named instances for more complex scenarios.

    fmt.Println(a.Render(42))

}
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,存储库“facebookgo/inject”现已存档 (9认同)
  • 此代码说明了这种方法具有不必要的复杂性。uber/dig 或 google/wire 是更好的方法。 (4认同)