DDD::domain::entity:value:聚合根

133 阅读5分钟

✅ DDD 的全称是 Domain-Driven Design,中文叫 领域驱动设计


📖 一、DDD 的基本定义

DDD(Domain-Driven Design) 是一种以“业务领域”为核心的软件设计思想。
它的核心目标是:
👉 用代码表达业务逻辑本身,而不是技术细节。


🧠 二、关键词拆解理解

单词含义对应代码层
Domain(领域)指业务范围或业务模型(如订单、用户、支付)internal/domain/
Driven(驱动)表示系统的设计、架构、代码组织,都围绕领域模型来驱动整个架构理念
Design(设计)指通过分层、抽象、建模,把复杂业务变得可维护、可扩展系统分层结构

🧱 三、DDD 的核心思想

一句话总结:

让开发者与业务专家“说同一种语言”,用代码直接表达业务规则。

它提倡:

  1. 以业务逻辑为中心,而不是数据库或框架;
  2. 通过模型(Entity、Value Object、Aggregate)表达业务概念
  3. 通过分层(Domain / Usecase / Data / Interface)实现解耦
  4. 通过 Repository 把领域模型与基础设施隔离

🧩 四、DDD 在代码层的典型结构(以 Kratos 为例)

internal/
├── domain/       # 领域层(实体、值对象、仓储接口)
│   └── order/
│       ├── entity.go
│       ├── value.go
│       └── repo.go
├── usecase/      # 应用层(用例逻辑)
│   └── order_usecase.go
├── data/         # 基础设施层(实现仓储、数据库、缓存等)
│   └── order_repo.go
└── service/      # 接口层(gRPC/HTTP 控制器)
    └── order_service.go

🔄 五、和传统分层的区别

对比点传统三层架构DDD 分层架构
关注点技术(Controller、Service、DAO)业务(Domain、Usecase、Repository)
代码驱动力框架驱动领域驱动
可测试性较低高(接口分层、Mock仓储)
可维护性逻辑易散落高内聚、低耦合
适用场景简单 CRUD 系统复杂业务系统(如订单、结算、审批流程)

💬 六、总结一句话:

DDD(Domain-Driven Design) 是一种让软件结构直接反映业务逻辑的设计方法。
它通过“领域模型 + 明确分层 + 接口解耦”,让系统既符合业务,又具备良好的可维护性和可演进性。


是否希望我接着帮你画一张「DDD 四层架构关系图(含箭头和职责说明)」?
👉 一张图你就能完全看懂 DDD 各层之间的作用和调用方向。

You said:

Aggregate 举个例子

ChatGPT said:

好的,我们来讲 Aggregate(聚合) ,这是 DDD 里一个非常重要但容易混淆的概念,我会从本质、特征、例子讲清楚。


1️⃣ 什么是 Aggregate(聚合)

聚合 = “一组相关对象的集合,它们作为一个整体被管理,有一个根对象(Aggregate Root)对外提供访问”。

特点:

  1. **聚合根(Aggregate Root)**是唯一对外暴露的对象,外部只能通过它操作聚合内部的对象;
  2. 聚合内部对象(实体或值对象)只对聚合根可见;
  3. 聚合保证业务规则的一致性。

2️⃣ 举例:订单系统

在订单系统中,一个典型聚合是 Order(订单聚合)

Order (Aggregate Root)
├── OrderItem (实体)
├── Address (值对象)
└── PaymentInfo (值对象或实体)

解释:

  • Order 是聚合根,对外提供创建、支付、取消等行为;
  • OrderItem 是聚合内部实体,只能通过 Order 修改;
  • Address、PaymentInfo 是值对象,属于 Order 聚合的一部分;
  • 外部系统(如 UseCase、Service)不能直接修改 OrderItem,必须通过 Order 进行操作。

3️⃣ Go 代码示例

// order.go
package order

import "time"

// 聚合根
type Order struct {
	ID        string
	UserID    string
	Items     []OrderItem
	Address   Address
	Status    string
	CreatedAt time.Time
}

// 内部实体
type OrderItem struct {
	ProductID string
	Quantity  int
	Price     float64
}

// 值对象
type Address struct {
	Province string
	City     string
	Street   string
	ZipCode  string
}

// 聚合根行为
func (o *Order) AddItem(item OrderItem) {
	o.Items = append(o.Items, item)
}

func (o *Order) Cancel() {
	if o.Status != "Paid" {
		o.Status = "Cancelled"
	}
}

func (o *Order) Pay() {
	o.Status = "Paid"
}

✅ 关键点:

  • Order 是唯一聚合根,外部只能通过它添加商品、支付或取消订单;
  • OrderItem 不暴露在外部,保证数据一致性;
  • Address 作为值对象不可变。

4️⃣ 聚合和仓储的关系

通常 仓储只针对聚合根

type OrderRepository interface {
	Save(order *Order) error
	FindByID(id string) (*Order, error)
}

注意:你不会单独给 OrderItem 创建仓储,因为它是聚合内部对象。


5️⃣ 总结

名称作用示例
Aggregate Root聚合唯一对外访问对象Order
Entity(内部)聚合内部实体OrderItem
Value Object聚合内部不可变对象Address、PaymentInfo
Repository针对聚合根访问数据OrderRepository

一句话理解:

聚合 = 一棵树,聚合根是树根,外界只能通过树根访问叶子节点,保证一致性。


如果你需要,我可以帮你画一张 Order 聚合示意图,把 聚合根、内部实体、值对象 的关系直观展示出来,让概念更清晰。

你希望我画吗?

You said:

聚合根是一个 entity 吗

ChatGPT said:

✅ 是的,聚合根(Aggregate Root)本质上是一个实体(Entity) ,但它有一个特殊职责:它是聚合内部所有对象对外的唯一入口。

我们来拆开理解:


1️⃣ 实体 vs 聚合根

特性Entity(实体)Aggregate Root(聚合根)
唯一标识有唯一 ID也有唯一 ID(本质上是实体)
作用域单个对象管理一个聚合内部的所有实体和值对象
外部访问可以直接被外部访问外部只能通过聚合根访问内部对象
行为可以包含业务方法包含业务方法,并保证聚合一致性

2️⃣ 聚合根的职责

  1. 保证聚合内部的一致性

    • 比如 Order 聚合根负责确保 OrderItem 的数量、价格总额、状态合法性。
  2. 对外唯一入口

    • 外部只能通过 Order 操作订单,不能直接修改 OrderItem
  3. 持久化的单位

    • 仓储(Repository)只针对聚合根,而不是聚合内部对象。

3️⃣ 代码示例

// 聚合根
type Order struct {  // <- 它是一个实体
    ID     string    // 唯一标识
    Status string
    Items  []OrderItem
}

// 内部实体
type OrderItem struct {
    ProductID string
    Quantity  int
}

// 聚合根方法
func (o *Order) AddItem(item OrderItem) {
    o.Items = append(o.Items, item)
}

func (o *Order) Cancel() {
    if o.Status != "Paid" {
        o.Status = "Cancelled"
    }
}

✅ 特点:

  • Order 是实体:有 ID、可以被识别;
  • Order 是聚合根:外部只能通过它来操作 Items,保证聚合完整性;
  • OrderItem 是聚合内部实体,不直接暴露给外部。

4️⃣ 小结

聚合根 = 一个特殊的实体,它管理聚合内部对象、保证一致性,并对外暴露操作接口;
聚合内部实体和值对象只在聚合根内部可见,不直接对外暴露。