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

报告相同问题?

悬赏问题

  • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作
  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行