目录
- 依赖注入
- Wire简介
- 带参数依赖
- 总结
Go相对Java和C++是较新的语言,但也有诸多优秀特性及生态库。本文介绍大多数软件工程中常用的功能:依赖注入。首先介绍什么是依赖注入,go实现库wire与其他语言的差异。然后通过简单示例实现依赖注入,简化代码、提升可读性。
依赖注入
依赖注入是一种对象接收它所依赖的其他对象(称为依赖项)的技术。通常,接收对象称为客户端,传入(“注入”)对象称为服务。
为了更好理解,下面通过一个简单示例进行说明:
package main import ( "fmt" ) type Message string type Greeter struct { Message Message } type Event struct { Greeter Greeter } func GetMessage() Message { return Message("Hello world!") } func GetGreeter(m Message) Greeter { return Greeter{Message: m} } func (g Greeter) Greet() Message { return g.Message } func GetEvent(g Greeter) Event { return Event{Greeter: g} } func (e Event) Start() { msg := e.Greeter.Greet() fmt.Println(msg) } func main() { message := GetMessage() greeter := GetGreeter(message) event := GetEvent(greeter) event.Start() }
上面代码有mepythonssage, greeter, event;GetMessage函数返回消息,GetGreeter函数接受消息返回greeter,getEvent函数接受返回greeter返回事件。事件还有一个方法start输出消息。
在main函数中,首先创建消息,然后作为依赖传入greeter,最后传给事件。运行程序可以看到输出“Hello world!",这是相对较浅的依赖图,但也能看到其复杂性,这也是依赖注入库wire的价值体现。
Wire简介
Wire是代码依赖工具,它没有采用反射机制或运行时状http://www.devze.com态,使用Wire可以有效避免手动编写硬代码依赖。Wire在编译时生成源码,官方文档描述: “In Wire, dependencies between components are represented as function parameters, encouraging explicit initialization instead of global variables.” (在Wire中组件之间的依赖关系表示为函数参数,优先采用显式初始化而不是全局变量。)
通过下面命令安装wire:go get github.com/google/wire/cmd/wire
;全局安装wire,为后续使用wire命令生成代码:go install github.com/google/wire/cmd/wire
下面我们使用Wire作为依赖注入工具重构上面代码,新增wire.go文件,增加下面代码:
//go:build wireinject // +build wireinject package main import "github.com/google/wire" func InitializeEvent() Event { wire.Build(GetMessage, GetGreeter, GetEvent) return Event{} }
首先导入wire,然后创建InitializeEvent函数,该返回在main函数中调用的事件。函数体内调用wire,在构建器方法内传入所有依赖,注意,传入依赖与顺序无关。然后返回空事件,无需担心,所有交给Wire。
注意,文件上面的注释告诉Go在编译时忽略该文件,要确保该注释行后面增加一行空行。
下面是main函数代码:
func main() { event := InitializeEvent() event.Start() }
现在成功地把main函数代码降为两行。在wire.go代码目录下,执行wire命令,wire会生成wire_gen.go文件:
// Code generated by Wire. DO NOT EDIT. //go:generate go run github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject package main // Injectors from wire.go: func InitializeEvent() Event { message := GetMessage() greeter := GetGreeter(message) event := GetEvent(greeter) return event }
同样生成的文件上面注释与wire.go文件相比多了!,表示wire在编译时忽略,go编译时启动。这是运行main函数正确输出结果。
带参数依赖
如果需要动态传入消息作为参数呢?下面我们修改GetMessage函数:
func GetMessage(text string) Message { return Message(text) }
再次运行wire命令,可以看到wire_gen.go 代码也有相应修改:
// Code generated by Wire. DO NOT EDIT. //go:generate go run github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject package main // Injectors from wire.go: func InitializeEvent(text string) Event { message := GetMessage(javascripttext) greeter := GetGphpreeter(message) event := GetEvent(greeter) return event }
现在修改main.go代码:
func main() { event := InitializeEvent("Hello golang") event.Start() }
运行结果与期望一致。
如果修改wire.go代码, 模拟缺少部分依赖:
func InitializeEvent(text string) Event { wire.Build(GetMessage, GetEvent) return Event{} }
执行wire命令,会正确提示少了相应的依赖:
inject InitializeEvent: no provider found for demo01.Greeter needed by demo01.Event in provider "GetEvent"
总结
本文介绍了基本wire概念,并通过简单示例介绍动态实现依赖注入。但一般wire会在较大项目使用,更多高级功能参考官方文档:https://github.com/google/wire/blob/maiphpn/docs/guide.md#advanced-features 。
到此这篇关于Go依赖注入工具wire的文章就介绍到这了,更多相关Go依赖注入工具wire内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
精彩评论