Go 语言中怎么使用依赖注入

news/发布时间2024/5/18 16:50:30

Go 语言中怎么使用依赖注入?

大家好,我是 frank。
欢迎大家点击标题下方蓝色文字「Golang 语言开发栈」关注公众号。
公众号主页点击右上角三个点图标,
设为星标,第一时间接收推送文章。
文末扫码,加群一起学 Golang 语言。

01 

介绍

在 Go 语言项目开发中,我们处理组件层级之间的依赖关系时,通常我们会先在依赖层级的代码中实例化被依赖层级,然后调用它的方法,即依赖方需要主动获取被依赖方。

但是,当被依赖层级的代码发生变化时,依赖层级的代码也需要修改,耦合性比较高,代码不方便扩展。

所谓依赖注入,即依赖方不再需要主动获取被依赖方,而是被依赖方主动传递给依赖方。

本文我们介绍 Go 语言怎么使用依赖注入。

02 

Go 语言使用依赖注入

在 Go 语言中,怎么使用依赖注入呢?我准备以 clean arch 架构的代码讲解。

推荐读者朋友们先阅读我之前写的一遍文章 「Go 语言整洁架构实践」。

参照 Bob 大叔的一篇关于整洁架构的文章 The Clean Architecture,我们分 4 个层级:

  1. Models
  2. Repository
  3. Usecase
  4. Delivery

限于篇幅,本文主要介绍在 Go 语言中使用构造函数的方式实现依赖注入,读者朋友们可以在留言区分享其它实现方式。

示例代码:

// Models 层
type Todolist struct {
 Id      int64  `json:"id"`
 Title   string `json:"title"`
 Status  int    `json:"status"`
 Created int    `json:"created"`
 Updated int    `json:"updated"`
}

type TodoListRepository interface {
 Create(ctx context.Context, t *Todolist) (err error)
}

type TodoListUsecase interface {
 Create(context.Context, *Todolist) (err error)
}

// Repository 层
type mysqlTodoListRepository struct {
 Conn *sql.DB
}

func NewMysqlTodoListRepository(Conn *sql.DB) models.TodoListRepository {
 return &mysqlTodoListRepository{Conn}
}

func (m *mysqlTodoListRepository) Create(ctx context.Context, t *models.Todolist) (err error) {
 // ...
 return
}

// Usecase 层
type todoListUsecase struct {
 todoListRepo models.TodoListRepository
}

func NewTodoListUsecase(t models.TodoListRepository) models.TodoListRepository {
 return &todoListUsecase{
  todoListRepo: t,
 }
}

func (tl *todoListUsecase) Create(ctx context.Context, t *models.Todolist) (err error) {
 if t.Title == "" {
  return fmt.Errorf("illegal parameter")
 }
 return tl.todoListRepo.Create(ctx, t)
}

// Delivery 层
type TodoListHandler struct {
 TodoListUsecase models.TodoListUsecase
}

func NewTodoListHandler(r *gin.Engine, todoListUsecase models.TodoListUsecase) {
 handler := &TodoListHandler{
  TodoListUsecase: todoListUsecase,
 }
 r.POST("/create", handler.Create)
 r.Run()
}

// main 函数
func main() {
 conn, err := sql.Open(`mysql`, "root:root@tcp(127.0.0.1:3306)/todolist")
 if err != nil {
  log.Fatal(err)
 }
 r := gin.Default()
 todoListRepository := mysql.NewMysqlTodoListRepository(conn)
 todoListUsecase := usecase.NewTodoListUsecase(todoListRepository)
 http.NewTodoListHandler(r, todoListUsecase)
}

阅读上面这段代码,我们可以发现 Repository 层依赖数据库驱动 conn,Usecase 层依赖 Repository 层,Delivery 层依赖 Usecase 层。

以 Repository 层和 Usecase 层为例,我们可以发现 Usecase 层通过构造函数 func NewTodoListUsecase(t models.TodoListRepository) models.TodoListRepository 将其依赖项 models.TodoListRepository 以参数的形式传递过来,并将其放入 todoListUsecase 结构体中。

所以,我们使用 Usecase 层的构造函数 NewTodoListUsecase 创建 Usecase 对象时,需要先使用 Repository 层的构造函数 NewMysqlTodoListRepository 创建 Repository 对象,并将其以参数的形式传递给 Usecase 层的构造函数 NewTodoListUsecase

通过依赖注入的方式,可以有效降低组件层级之间的耦合性,方便代码的扩展。比如示例代码中 Repository 层的方法修改代码,不会影响 Usecase 层的代码。

03 

依赖注入工具

除了手写依赖注入代码,我们也可以使用依赖注入工具,开源社区有很多依赖注入工具,其中比较流行的主要有以下 3 个。

Google 开源的依赖注入工具 Wire[1],它是一个代码生成工具,也就是说它是在编译时自动生成代码。

另外 2 个依赖注入工具是在运行时基于 Go 反射实现,分别是 uber开源的依赖注入工具 Dig[2] 和 facebook 开源的依赖注入工具[3]

读者朋友们可以根据实际开发中的需求,选择合适的工具。

04 

总结

读者朋友们可能已经发现,依赖注入实际上就是面向对象五大原则之一,依赖倒置原则的实现方式。

我们可以在 Go 项目开发中,使用依赖注入的方式,降低组件层级之间的代码耦合性,使代码更方便扩展。

推荐阅读

  1. Go 1.22 对 net/http.ServeMux 多路复用器新增两个增强功能
  2. Prometheus Go client library 详解
  3. Go 语言使用标准库 sync 包的 mutex 互斥锁解决数据竞态
  4. GORM V2 安装和连接 MySQL
  5. Go 语言开源项目使用的函数选项模式
参考资料[1]

Google 开源的依赖注入工具 Wire: https://github.com/google/wire

[2]

uber开源的依赖注入工具 Dig: https://github.com/uber-go/dig

[3]

facebook 开源的依赖注入工具: https://github.com/facebookarchive/inject

 

图片

扫描二维码或回复「微信群」,加入微信群

图片

点「赞」和「在看」是最大的支持👇

图片

👇更多精彩内容,请点击阅读原文」

Golang语言 · 目录
上一篇Go 1.22 标准库 slices 新增函数和一些旧函数增加新特性
阅读原文
阅读 960
 
 
写留言
 
 
 
 
 
 
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/11872740.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

2-25. 背包 UI 显示

InventoryUI将它拖动到 Canvas 上面的 Inventory增加 Player Slots 我们希望物品被拾取的时候,首先进入下面的背包,然后才进入上面的背包,所以 Player Slots 需要先拖动下面的格子,再拖动上面的格子修改 PlayerBag 的数量因为下面有10个格子,上面有16个格子,所以一共有 2…

ARM指令SVE、SME在MLIR中的实现方式

ARM指令SVE、SME在MLIR中的实现方式 1. MLIR基本概念 MLIR(Multi-Level Intermediate Representaion,多级中间表示)是一种用来构建可重用和可扩展编译的新方法。MLIR的设计初衷是为了解决软件碎片化问题,改进异构硬件的编译,显著减少构建特定领域编译器的成本以及帮助连接…

交通部视频云联网项目中视频上云网关技术选型参考

常见的有3个选择:1、 比特大陆/算能的SC5+卡单张卡视频转码能力(1080P到CIF)是54路,这是官方给出的性能指标。2、 寒武纪MLU365-D2视频卡 这张卡是单卡50路左右。3、涌现的Seirios-P4N卡这张卡单卡1080P可处理64路,以下是这张卡的性能截图,请参考: 还有一个小细节挺有意…

Golang: Sync.Pool 源码解析

Sync.Pool提供了对象池的功能,通过复用对象减少内存分配和垃圾回收压力。 Pool结构包含local数组存储P对应的本地对象池,New函数生成对象。 poolLocal与每个P绑定,private用于快速处理,shared作为大容量存储和窃取。Put方法将对象放回池中。Sync.Pool Sync.Pool需要提前了解…

实景三维在园林养护管理上的应用

随着城市化进程的加速和人民生活水平的提高,城市园林绿化成为了提升城市品质和居民生活质量的重要因素。园林养护管理工作作为保证园林绿化效果和持续性的重要环节,其科学化、精细化管理需求日益凸显。在这样的背景下,实景三维技术的应用成为了园林养护管理领域的一次革命性…

浮点数(小数)在计算机中如何用二进制存储?

【摘要说明】本篇文章自启发博文中摘录了几张图,若涉及侵权,请与我联系,我将尽快处理。 如果文中阐述不全或不对的,多多交流。【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18107586 出自【进步*于辰的博客】…