如何在 Go 中实践领域驱动设计(DDD):手把手保姆及教程

Golang

📌 本文将手把手带你用 Go 实现一个在线 Tavern(酒馆)系统,逐步构建 DDD 的核心组件:实体(Entity)、值对象(Value Object)、聚合(Aggregate)、仓储(Repository)、工厂(Factory)和服务(Service),全程配合图解说明,拒绝“概念轰炸”。

picture.image


🧠 为什么需要 DDD?

微服务虽好,但无组织地拆分服务 = 制造分布式单体 👉 复杂度爆炸💥
DDD 的核心思想是:让代码结构反映业务领域,与领域专家共建「通用语言」(Ubiquitous Language),避免工程师凭空臆想业务逻辑。

✅ 举例:你不会把“常来喝酒的人”叫 Drinker,领域专家会称之为 Customer —— 这就是通用语言的力量。


🛠️ 项目初始化

mkdir ddd-go && cd ddd-go
go mod init github.com/yourname/ddd-go

目录结构预览:

ddd-go/
├── entity/          # 实体:跨域共享的可变身份对象
├── aggregate/       # 聚合根 + 值对象
├── domain/
│   ├── customer/    # 子域:客户管理
│   └── product/     # 子域:商品管理
├── service/         # 应用服务层
└── ...

🔑 核心概念实现

1️⃣ Entity(实体) vs Value Object(值对象)

特性EntityValue Object
是否有唯一 ID✅ 是❌ 否
状态是否可变✅ 可变❌ 不可变(创建后即冻结)
相等性判断ID 相等所有字段相等
// entity/person.go
type Person struct {
	ID   string // ← 唯一标识
	Name string
	Age  int
}
// entity/transaction.go(值对象)
type Transaction struct {
	Amount float64
	At     time.Time
	// 无 ID 字段!
}

2️⃣ Aggregate(聚合)

聚合 = 1 个聚合根(根实体) + 若干实体/值对象
外部只能通过聚合根访问内部对象
聚合内强一致性,聚合间最终一致性

// aggregate/customer.go
type Customer struct {
	person     *entity.Person     // 根实体(ID 来源)
	products   []entity.Product
	orders     []Transaction      // 值对象
}

func (c *Customer) ID() string { return c.person.ID } // ← 暴露根 ID
func (c *Customer) ChangeName(name string) { c.person.Name = name }

⚠️ 注意:字段小写 → 包外不可访问;避免在聚合上加 json/bson tag(解耦存储实现)


3️⃣ Factory(工厂)

封装复杂对象创建逻辑,保证聚合初始状态合法:

// aggregate/customer.go
func NewCustomer(name string) (*Customer, error) {
	if name == "" {
		return nil, errors.New("name is required")
	}
	id := uuid.New().String()
	return &Customer{
		person: &entity.Person{ID: id, Name: name},
	}, nil
}

✅ 优势:校验前置、ID 自动生成、未来可扩展(如注册事件)


4️⃣ Repository(仓储)

接口定义在 domain 层,实现下沉到 infra 层 —— 实现「依赖倒置」:

// domain/customer/repository.go
type CustomerRepository interface {
	Get(id string) (*Customer, error)
	Add(c *Customer) error
	Update(c *Customer) error
}

内存实现(开发/测试用)

// domain/customer/memory/memory.go
type MemoryRepository struct {
	customers map[string]*Customer
	mu        sync.RWMutex
}

func (m *MemoryRepository) Get(id string) (*Customer, error) {
	m.mu.RLock()
	defer m.mu.RUnlock()
	c, ok := m.customers[id]
	if !ok { return nil, ErrCustomerNotFound }
	return c, nil
}

MongoDB 实现(生产用)

// domain/customer/mongo/mongo.go
type MongoRepository struct {
	coll *mongo.Collection
}

func (m *MongoRepository) Get(id string) (*Customer, error) {
	var doc mongoCustomer // ← 内部转换结构,避免污染 aggregate
	err := m.coll.FindOne(context.TODO(), bson.M{"_id": id}).Decode(&doc)
	if err != nil { return nil, err }
	return doc.ToAggregate(), nil // ← 转为领域对象
}

✅ 优势:无缝切换存储引擎!测试用内存,上线换 MongoDB,业务代码零修改。


5️⃣ Service(应用服务)

聚合业务流程,协调多个 Repository:

// service/order.go
type OrderService struct {
	customerRepo domain.CustomerRepository
	productRepo  domain.ProductRepository
}

func NewOrderService(opts ...OrderOption) *OrderService {
	s := &OrderService{}
	for _, opt := range opts {
		opt(s)
	}
	return s
}

// 配置函数示例(优雅可扩展!)
func WithMemoryCustomerRepository() OrderOption {
	return func(s *OrderService) {
		s.customerRepo = memory.NewCustomerRepository()
	}
}

func (s *OrderService) CreateOrder(customerID string, productIDs []string) (float64, error) {
	customer, _ := s.customerRepo.Get(customerID)
	// ... 查询商品、扣库存、生成交易 ...
	return totalPrice, nil
}

🏁 最终架构:Tavern 服务

// service/tavern.go
type Tavern struct {
	orderService *OrderService
	// billingService *BillingService // ← 未来可扩展
}

func NewTavern(orderSvc *OrderService) *Tavern {
	return &Tavern{orderService: orderSvc}
}

func (t *Tavern) Serve(customerName string, productNames []string) error {
	customer, _ := t.orderService.RegisterCustomer(customerName)
	_, err := t.orderService.CreateOrder(customer.ID(), productNames)
	return err
}

✅ 收获

DDD 概念Go 实现要点
实体有 ID、可变状态、包级可见
值对象无 ID、不可变、用值语义
聚合封装+不变性保障,仅暴露根 ID
仓储接口定义在 domain,实现下沉
工厂集中创建逻辑 + 校验前置
服务编排 Repository,无状态

💡 记住:DDD 是一种思维方式,不是语法规范。
重点在于 与领域专家共建模型,而非纠结 entity 还是 model 文件夹命名 😄


0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
vivo 容器化平台架构与核心能力建设实践
为了实现规模化降本提效的目标,vivo 确定了基于云原生理念构建容器化生态的目标。在容器化生态发展过程中,平台架构不断演进,并针对业务的痛点和诉求,持续完善容器化能力矩阵。本次演讲将会介绍 vivo 容器化平台及主要子系统的架构设计,并分享重点建设的容器化核心能力。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论