Go语言wire依赖学习笔记
一、依赖注入、控制反转
在使用Wire之前,先简单解释一下这两个名词是啥意思。
控制反转(Inversion of Control, IoC),是面向对象编程 中的一种设计原则,是一种编写程序时对代码结构的设计思想,其核心作用是降低代码的耦合度。而依赖注入(Dependency Injection, DI)则是实现这种思想的一种最常用的手段,是一种解决依赖性问题的设计模式。具体的文字定义就不贴了。
假如现在要编写代码完成一个吃早餐的操作,采用手动依赖注入。
type Breakfast struct {
Food string
}
func NewBreakfast(food string) Breakfast {
return Breakfast{Food: food}
}
以上代码定义了一个早餐类型,创建它时返回一个具体的早餐品种。
再定义一个吃早餐的人,返回人名:
type Person struct {
Name string
}
func NewPerson(name string) Person {
return Person{Name: name}
}
最后就可以编写吃早餐的动作了:
type EatBreakfast struct {
Person Person
Breakfast Breakfast
}
func NewEatBreakfast(p Person, b Breakfast) EatBreakfast {
return EatBreakfast{p, b}
}
func (e EatBreakfast) Eat() {
fmt.Printf("%s eats %s for breakfast!\n", e.Person.Name, e.Breakfast.Food)
}
在main方法中调用:
func main() {
breakfast := NewBreakfast("Bread")
person := NewPerson("XiaoMing")
eatBreakfast := NewEatBreakfast(person, breakfast)
eatBreakfast.Eat()
}
调用后可以获得输出:
XiaoMing eats Bread for breakfast!
分析
- 在这个案例中,代码有两个层级:EatBreakfast一层,Person和Breakfast为另一层,EatBreakfast依赖Person和Breakfast。为了最终调用到EatBreakfast中的Eat方法,必须要我们手动一个一个创建Person和Breakfast。在项目规模变得庞大的时候,这种手动创建依赖,再组合的方式就会变得非常繁琐。
接下来,就可以引入Wire这个工具了!
二、Wire快速使用
1. 简介
Wire 是一个轻巧的 Golang 依赖注入工具。它由 Go Cloud 团队开发,通过自动生成代码的方式在编译期完成依赖注入。它不需要反射机制,后面会看到, Wire 生成的代码与手写无异。
2. 安装与使用
在控制台里输入以下命令即可安装。
go get github.com/google/wire/cmd/wire
将...\go\pkg\mod\github.com\google\wire@v0.5.0\cmd\wire包下的代码生成出一个wire.exe,然后将其添加进环境变量中,这样后续就可以直接使用wire工具了。
还是以上面的代码为例子,看看 Wire 应该如何使用。但首先要修改一下 Breakfast 里的代码,去掉接收参数(wire 不允许不同的注入对象拥有相同的类型。google 官方认为这种情况,是设计上的缺陷。不过这种情况下,可以通过类型别名来将对象的类型进行区分。)
type Breakfast struct {
Food string
}
func NewBreakfast() Breakfast {
return Breakfast{Food: "bread"}
}
然后编写一个wire.go文件(名称其实可以随便起)
package main
import "github.com/google/wire"
func InitializeEvent(f string) EatBreakfast {
wire.Build(NewPerson, NewBreakfast, NewEatBreakfast)
return EatBreakfast{}
}
在控制台输入
wire gen wire.go
就会生成 wire_gen.go 文件,会惊奇的发现里面的内容与我们手动编写的依赖注入几乎一样。
再次修改 main 方法:
func main() {
eatBreakfast := InitializeEvent("XiaoMing")
eatBreakfast.Eat()
}
同样也可以输出正确的结果。
三、Wire的基础概念
两个基础概念:Provider(构造器)和 Injector(注入器)
- Provider 实际上就是生成组件的普通方法,这些方法接收所需依赖作为参数,创建组件并将其返回。我们上面例子的 NewBreakfast 就是 Provider。
- Injector 可以理解为 Providers 的连接器,它用来按依赖顺序调用 Providers 并最终返回构建目标。我们上面例子的 InitializeEvent 就是 Injector。
具体在项目中如何使用,可以阅读Go 语言官方依赖注入工具 Wire 使用指北
四、总结
Wire 是一个强大的依赖注入工具,开发项目时,可以很好协助我们完成复杂对象的构建组装。但也有一些需要注意的使用问题,比如上文提到的相同类型初始化会失败的问题。