依赖注入是软件工程中经常使用到的一种技术,它提供了一种控制反转的机制,把控制权利交给了调用方。调用方来决定使用哪些参数,哪些对象来进行具体的业务逻辑。

依赖注入的本质其实是为了将组件的创建与其依赖的创建分离

实现原理:

  1. 通过反射读取对象的依赖(golang是通过tag实现)
  2. 在容器中查找有无该对象实例
  3. 如果有该对象实例或者创建对象的工厂方法,则注入对象或使用工厂创建对象并注入
  4. 如果无该对象实例,则报错

好处:
1 它让调用方更灵活。
2 大量减少定义类型的代码量
3 增加代码的可用性,因为调用方只需要关注它需要的参数,不需要顾及它不需要的参数了。

正常我们创建一个对象,首先需要构建对象的构造函数,调用时将入参加入进去,然后其中一旦有一个入参需要更改,所有函数的入参都需要修改:

type Cat struct {
    color String
}

func (cat *Cat) Start() {
    pass
}

func NewCat() *Cat {
    return &Cat{
        color :      "read"
    }
}



type Person struct {
    cat *Cat
}

func (service *Person) Start() []*Person {
    service.cat.Start()
}

func NewPerson(cat *Cat) *Person{
    return &Person{cat: cat}
}

func main() {
    cat := NewCat()
    person := NewPerson(cat)

    person.Satrt()
}

而如果使用以来注入的方式:

type Cat struct {
    color String
}

func (cat *Cat) Start() {
    pass
}

func NewCat() *Cat {
    return &Cat{
        color :      "read"
    }
}



type Person struct {
    cat *Cat
}

func (service *Person) Start() []*Person {
    service.cat.Start()
}

func NewPerson(cat *Cat) *Person{
    return &Person{cat: cat}
}
func BuildContainer() *dig.Container {
    container := dig.New()
    container.Provide(NewCat)
    container.Provide(NewPerson)
    return container
}
func main() {
    container := BuildContainer()

    err := container.Invoke(func(person *Person) {
        person.Start()
    })

    if err != nil {
        panic(err)
    }
}

这个虽然看起来没有简化多少,但是如果依赖的比较多的时候,就需要初始化一堆对象,然后调用对应的函数,而依赖注入:

persionCatCatNewCatNewCatNewCatCat*persionInvoke

这个就是依赖注入的本质,