依赖注入

2023/05/10 go探索发现 共 2059 字,约 6 分钟

依赖注入

依赖注入(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帮我们管理了所有依赖对象的创建,以及后续的生命周期。

文档信息

Search

    Table of Contents