1. 课程导学:依赖注入与领域解耦的核心价值、课程目标与学习路径

在大型 Go 项目中,领域逻辑与基础设施的耦合是架构腐化的首要诱因。依赖注入(Dependency Injection, DI)并非单纯的“传参技巧”,而是一种在领域边界实施解耦的架构模式。本章作为课程起点,将阐明 DI 在 DDD 分层中的核心价值、本课程的具体目标以及推荐的学习路径。

1.1 依赖注入的核心价值:从“硬编码依赖”到“边界反转”

传统 Go 项目中,领域层直接调用数据库、缓存或外部服务,导致领域逻辑被基础设施细节“污染”。依赖注入通过将依赖的创建与使用分离,实现了依赖倒置原则(DIP):领域层只依赖抽象接口,而非具体实现。

核心收益:
  • 领域纯净性:领域层不包含任何 import 数据库驱动、HTTP 客户端等基础设施包。
  • 可测试性:领域逻辑可脱离真实基础设施进行单元测试,仅需 Mock 接口。
  • 可替换性:替换数据库、消息队列或第三方 SDK 时,无需修改领域层代码。
  • 关注点分离:对象的生命周期管理(创建、复用、销毁)由 DI 容器统一处理。

1.2 课程目标:掌握 Go 项目中的 DI 与 DDD 协同实践

本课程并非泛泛讲解 DI 概念,而是聚焦于 Go 语言特性与 DDD 战术模式结合下的具体落地方法。完成本课程后,你将能够:

目标维度 具体能力 对应章节
架构设计 识别领域边界,设计符合 DDD 的分层架构与模块划分 第 2-5 章
DI 实现 使用构造函数注入、参数对象、Wire 等工具实现手动与自动 DI 第 6-10 章
领域解耦 通过 DI 将仓储、事件总线、领域服务等基础设施从领域层剥离 第 11-15 章
测试策略 利用 DI 编写可 Mock 的领域层单元测试与集成测试 第 16-18 章
工程实践 在微服务、单体应用及遗留系统中渐进式引入 DI 与 DDD 第 19-25 章

1.3 依赖注入在 DDD 分层中的位置

下图展示了依赖注入如何在 DDD 经典四层架构中扮演“边界胶水”角色,将领域层与基础设施层解耦:

依赖注入在 DDD 分层中的解耦位置 领域层(Domain) 实体、值对象、聚合根 领域服务、仓储接口 应用层(Application) 用例编排、DTO 转换 基础设施层(Infrastructure) 数据库、缓存、消息队列 接口层(Interface) HTTP Handler、gRPC 服务 依赖注入 (实现依赖倒置) 关键原则 领域层定义接口 基础设施层实现接口 DI 容器注入实现 解耦效果 领域层不 import 数据库 替换实现无需改领域
架构洞察:上图中,依赖注入的箭头方向与调用方向相反。领域层定义仓储接口(如 UserRepository),基础设施层实现该接口,DI 容器在应用层启动时将具体实现注入到领域服务中。这种“接口在领域、实现在基础”的模式,是 DDD 与 DI 结合的核心。

1.4 学习路径:从基础到实战的阶梯式设计

本课程共 30 章,分为四个阶段,建议按顺序学习:

  1. 基础篇(第 1-5 章):理解 DI 与 DDD 的核心概念,搭建 Go 项目的基础分层结构。
  2. 工具篇(第 6-10 章):掌握手动 DI、Wire 代码生成、Google Wire 等主流 Go DI 工具的使用与选型。
  3. 实战篇(第 11-20 章):在真实业务场景中(订单、支付、库存)应用 DI 解耦领域边界,包含单元测试与集成测试。
  4. 进阶篇(第 21-30 章):处理循环依赖、生命周期管理、多模块 DI、微服务间 DI 边界等高级话题。

1.5 前置知识与工具准备

类别 要求 说明
Go 语言 熟悉 Go 语法、接口、结构体、包管理 至少 1 年以上 Go 开发经验
DDD 基础 了解实体、值对象、聚合、仓储等概念 第 2 章会快速回顾,但非零基础
开发环境 Go 1.21+、Git、Docker(可选) 所有示例在 Go 1.21 下测试通过
DI 工具 Wire(Google 官方) 第 7 章开始安装使用
注意:本课程不要求你已经是 DDD 专家,但建议在开始前阅读 Eric Evans 的《领域驱动设计》前两章,或至少理解“领域层不应依赖基础设施”这一核心原则。如果你对 Go 接口与包设计尚不熟练,建议先复习相关基础。

1.6 一个简单的 DI 示例:从耦合到解耦

以下代码展示了一个典型的“耦合”场景,以及通过 DI 实现解耦后的对比:

耦合版本(不推荐):

// 领域层直接依赖 MySQL 实现
type UserService struct {
    db *sql.DB  // 直接依赖具体数据库
}

func (s *UserService) GetUser(id int) (*User, error) {
    row := s.db.QueryRow("SELECT ...", id)
    // ...
}

DI 解耦版本(推荐):

// 领域层定义接口
type UserRepository interface {
    FindByID(id int) (*User, error)
}

// 领域服务只依赖接口
type UserService struct {
    repo UserRepository  // 依赖抽象
}

// 基础设施层实现接口
type MySQLUserRepository struct {
    db *sql.DB
}

func (r *MySQLUserRepository) FindByID(id int) (*User, error) {
    // 具体 SQL 实现
}

// 应用层负责注入
func NewUserService(repo UserRepository) *UserService {
    return &UserService{repo: repo}
}
关键变化:领域层不再 import database/sql,UserService 只依赖接口 UserRepository。测试时只需传入一个 Mock 实现即可。

1.7 本章小结