dongyuntao2000 2017-01-27 17:48
浏览 116
已采纳

Golang中有更好的依赖注入模式吗?

Given this code:

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)
}

Is the wiring of components together that's done in main the right way to wire a dependency together? It seems like I'm over using this a bit in my code. Is there a common pattern better than this, or am I overthinking it?

  • 写回答

4条回答 默认 最新

  • dousongqiang2585 2017-03-23 08:10
    关注

    Yes, the facebookgo inject library allows you to take your injected members and will wire up the graph for you.

    Code: https://github.com/facebookgo/inject

    Documentation: https://godoc.org/github.com/facebookgo/inject

    Here's a code example from the documentation:

    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))
    
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
  • ¥15 java 的protected权限 ,问题在注释里