自学内容网 自学内容网

Go语言依赖注入方式

在Go语言中,依赖注入(Dependency Injection,DI)是一种设计模式,允许你将对象的依赖关系在外部进行管理,而不是让对象自己创建或查找依赖。通俗来说就是把一个对象所需要的东西如方法或属性(统称依赖)从外面传递给它,而不是让这个对象自己去找或实现这些东西。这种模式可以帮助你构建更可维护、可测试的代码。Go语言本身没有像一些面向对象语言(如Java)那样内置的依赖注入框架,但你可以通过多种方式实现依赖注入。

一、构造函数注入

构造函数注入是最常见的依赖注入方式之一。你可以在对象的构造函数中通过参数传递依赖。

package main

import "fmt"

// 定义依赖接口
type Service interface {
    Serve() string
}

// 实现接口的具体类型
type MyService struct{}

func (s MyService) Serve() string {
    return "MyService is serving"
}

// 使用依赖的结构体
type Controller struct {
    service Service
}

// 构造函数,注入依赖
func NewController(s Service) *Controller {
    return &Controller{service: s}
}

// 封装控制器的方法调用依赖
// 外部不需要直接访问 service 字段。这是一种良好的编程实践,它隐藏了内部实现细节,保证了接口的最小暴露。
// 使用依赖注入的核心目的之一是解耦和灵活性。如果你在外部代码中直接访问 controller.service.Serve(),你实际上绕过了依赖注入的封装,HandleRequest 方法可以让你的代码更容易进行单元测试
// 灵活性。HandleRequest 可以对 Serve() 的调用进行一些额外的操作。将来如果你希望在调用 Serve() 之前或之后做一些其他处理,比如日志记录、权限检查、错误处理等,封装一个方法会更加方便
func (c *Controller) HandleRequest() {
    fmt.Println(c.service.Serve())
}

func main() {
    // service实现了Service接口,把service通过NewController构造函数注入到controller中
    service := MyService{}
    controller := NewController(service)
    controller.HandleRequest()
}

二、接口注入

你可以使用接口将依赖注入,这样可以更灵活地替换实现。

package main

import "fmt"

// 定义依赖接口
type Service interface {
    Serve() string
}

type MyService struct{}

func (s MyService) Serve() string {
    return "MyService is serving"
}

// Controller依赖于Service接口
// 结构体嵌入接口,嵌入是Go语言的一种特性,允许你将一个类型嵌入到另一个类型中,使其拥有嵌入类型的所有方法。
type Controller struct {
    Service
}

func main() {
    service := MyService{}
    // Controller嵌入了Service接口,意味着Controller结构体需要提供一个Service接口实现,即service
    controller := Controller{service}
    fmt.Println(controller.Serve())
    // 不建议fmt.Println(controller.Service.Serve())调用
    // Controller 嵌入了 Service 接口,嵌入结构体的所有方法会提升到外部结构体中
    // controller.Serve()这样代码更简洁、易读,符合Go语言的惯用方式
    // 有方法名冲突或出于调试目的可以controller.Service.Serve()调用
}

三、Setter注入

package main

import "fmt"

type Service interface {
    Serve() string
}

type MyService struct{}

func (s MyService) Serve() string {
    return "MyService is serving"
}

type Controller struct {
    service Service
}

// Setter 方法用于注入依赖
func (c *Controller) SetService(s Service) {
    c.service = s
}

func (c *Controller) HandleRequest() {
    fmt.Println(c.service.Serve())
}

func main() {
    service := MyService{}
    controller := Controller{}
    controller.SetService(service)
    controller.HandleRequest()
}

四、Google的Wire库

go install github.com/google/wire/cmd/wire@latest

使用 wire 生成依赖代码,基本步骤如下:

// wire_example.go
package main

import (
    "fmt"
    "github.com/google/wire"
)

// 定义Service
type Service interface {
    Serve() string
}

type MyService struct{}

func (s MyService) Serve() string {
    return "MyService is serving"
}

// Controller依赖Service
type Controller struct {
    service Service
}

// 构造函数
func NewMyService() Service {
    return &MyService{}
}

func NewController(s Service) *Controller {
    return &Controller{service: s}
}

// 使用wire生成依赖
func InitializeController() *Controller {
    wire.Build(NewMyService, NewController)
    return &Controller{}
}

func main() {
    controller := InitializeController()
    fmt.Println(controller.service.Serve())
}

运行 wire 命令后,wire.go 文件会生成代码,管理你的依赖。

wire


原文地址:https://blog.csdn.net/bocai_xiaodaidai/article/details/142986742

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!