依赖注入
依赖注入(Dependency Injection, DI)是一种设计模式,它可以减轻对象之间的耦合,提高代码的可测试性和可重用性。
看一下golang代码使用依赖注入的简单用法
package main
import (
"fmt"
)
// LogTail 是处理日志记录功能的接口
type LogTail interface {
Write(message string, file string) bool
}
// LocalFile 是一个实现 LogTail 接口的结构体
type LocalFile struct{}
func (lf *LocalFile) Write(message string, file string) bool {
fmt.Printf("Message saved to local file %s with message: %s\n", file, message)
return true
}
// Log 是依赖 LogTail 的记录日志结构体
type Log struct {
logTail LogTail
}
func NewLog(lt LogTail) *Log {
return &Log{logTail: lt}
}
func (l *Log) Record(message string, file string) bool {
return l.logTail.Write(message, file)
}
func main() {
localFile := &LocalFile{}
log := NewLog(localFile)
log.Record("Hello, Dependency Injection!", "test.log")
}
可以看到Log对象通过接口的方式与LocalFile对象实现了解耦。测试时很容易模式LogTail的实现。
这里体现的核心思想是类应该依赖于抽象,而不是依赖于具体的东西。假设Log对象有多个依赖的对象,Log对象不应该关注如何创建这些依赖对象,而是由外部的注入器来管理。
依赖注入库
我们看一下 https://github.com/samber/do是如何实现依赖注入的封装
samber/do uses Go 1.18+ generics instead of reflection and therefore is typesafe.
samber/do的核心功能
它提供了几个核心功能,包括:
- 服务注册
- 服务调用
- 健康检查
- shutdown处理 ….
可以通过injector.HealthCheck()
, injector.ShutDown()
来调用所有已经注入到注入器中的相关方法。只要实现了do.Healthcheckable interface
就会在调用的清单里。 healthcheck可以在起服时做健康检查,shutdown可以在停服时做优雅停服逻辑。
QuickStart
import (
"github.com/samber/do"
)
type EngineService interface{}
func NewEngineService(i *do.Injector) (EngineService, error) {
return &engineServiceImplem{}, nil
}
type engineServiceImplem struct {}
func NewCarService(i *do.Injector) (*CarService, error) {
engine := do.MustInvoke[EngineService](i)
car := CarService{Engine: engine}
return &car, nil
}
type CarService struct {
Engine EngineService
}
func (c *CarService) Start() {
println("car starting")
}
func main() {
injector := do.New()
// provides CarService
do.Provide(injector, NewCarService)
// provides EngineService
do.Provide(injector, NewEngineService)
car := do.MustInvoke[*CarService](injector)
car.Start()
// prints "car starting"
do.HealthCheck[EngineService](injector)
// returns "engine broken"
// injector.ShutdownOnSIGTERM() // will block until receiving sigterm signal
injector.Shutdown()
// prints "car stopped"
}
provide会注册CarService对象,参数需要传入New方法。MustInvoke可以通过范型传入对象类型获取对象的实例。可以看到injector帮我们管理了所有依赖对象的创建,以及后续的生命周期。
文档信息
- 本文作者:Beast
- 本文链接:https://beastpu.github.io/2023/05/10/go-09/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)