DDD架构学习指南:从入门到实战
目录
前言:为什么要学习DDD?
作为一名程序员,你是否遇到过这些问题:
- 业务逻辑散落在各个Service类中,难以维护?
- 代码中充斥着贫血模型,实体类只是数据容器?
- 业务专家说的话和代码实现完全是两个世界?
- 系统越来越复杂,但代码却越来越难以理解?
如果你有这些困扰,那么DDD(领域驱动设计)正是你需要的解决方案。
第一章:DDD核心思想
1.1 什么是DDD
DDD不是一种技术,而是一种思维方式:
- 以业务为中心,而不是以技术为中心
- 代码即文档,业务规则直接体现在代码中
- 建立通用语言,让技术人员和业务专家能够无障碍沟通
领域驱动设计是Eric Evans在2003年提出的软件设计方法论,其核心思想是将复杂的软件系统建模为业务领域的反映。DDD强调:
领域优先:以业务领域为设计的出发点和中心
模型驱动:通过领域模型来指导软件设计
协作沟通:建立开发团队与业务专家之间的通用语言
1.2 简单对比
传统方式(贫血模型)
只有数据,没有行为
type BankAccount struct {
ID string
Balance decimal.Decimal
Status string
}
业务逻辑在Service层
type BankService struct{}
func (s *BankService) Withdraw(accountID string, amount decimal.Decimal) error {
account := s.repo.FindByID(accountID)
if account.Status != "ACTIVE" {
return errors.New("账户未激活")
}
if account.Balance.LessThan(amount) {
return errors.New("余额不足")
}
account.Balance = account.Balance.Sub(amount)
return s.repo.Save(account)
}
问题分析:
- 领域对象只是数据容器,缺乏行为
- 业务逻辑分散在Service层,难以维护
- 违反了面向对象的封装原则
DDD方式(富领域模型)
既有数据,也有行为
type BankAccount struct {
id AccountID
balance Money
status AccountStatus
}
// 业务逻辑在领域对象内部
func (a *BankAccount) Withdraw(amount Money) error {
if !a.IsActive() {
return ErrAccountNotActive
}
if a.balance.LessThan(amount) {
return ErrInsufficientBalance
}
a.balance = a.balance.Subtract(amount)
return nil
}
func (a *BankAccount) IsActive() bool {
return a.status == AccountStatusActive
}
在这样的对比中:
- DDD方式中,业务规则(如"只有激活的账户才能取款")直接体现在代码中
- 代码读起来就像在描述业务流程
- 业务专家看到这样的代码也能理解
第二章:DDD战略设计(理解业务边界)
在深入代码之前,我们需要先理解业务。这就是DDD的战略设计。
2.1 领域(Domain)
定义:
你的软件要解决的业务问题空间
例子:
- 电商系统的领域:商品管理、订单处理、支付、物流
- 银行系统的领域:账户管理、转账、贷款、风控
2.2 子域(Subdomain)
定义:
领域的细分,通常分为三类

2.3 限界上下文(Bounded Context)
定义:
明确的概念边界,在此边界内,术语具有特定含义
例子:
同样是"商品"这个概念
- 在商品管理上下文中:商品 = 名称 + 价格 + 库存 + 描述
- 在订单上下文中:商品 = 商品ID + 购买数量 + 单价
- 在推荐上下文中:商品 = 商品ID + 类别 + 标签 + 销量
第三章:DDD战术设计(代码实现)
现在我们来看具体的代码实现模式。
3.1 实体(Entity)
定义:
有唯一标识,生命周期贯穿业务流程的对象
// 订单实体 - 有唯一ID,状态会变化
type Order struct {
id OrderID // 唯一标识
customerID CustomerID
items []OrderItem
status OrderStatus
totalAmount Money
createdAt time.Time
}
// 业务行为
func (o *Order) AddItem(productID ProductID, quantity int, unitPrice Money) error {
if o.status != OrderStatusDraft {
return ErrOrderNotEditable
}
item := OrderItem{
ProductID: productID,
Quantity: quantity,
UnitPrice: unitPrice,
}
o.items = append(o.items, item)
o.recalculateTotal()
return nil
}
func (o *Order) Confirm() error {
if len(o.items) == 0 {
return ErrEmptyOrder
}
o.status = OrderStatusConfirmed
return nil
}
3.2 值对象(Value Object)
定义:
没有唯一标识,通过属性值区分的不可变对象
// 金额值对象
type Money struct {
amount decimal.Decimal
currency string
}
// 值对象是不可变的,操作返回新对象
func (m Money) Add(other Money) Money {
if m.currency != other.currency {
panic("currency mismatch") // 简化处理
}
return Money{
amount: m.amount.Add(other.amount),
currency: m.currency,
}
}
func (m Money) Multiply(factor int) Money {
return Money{
amount: m.amount.Mul(decimal.NewFromInt(int64(factor))),
currency: m.currency,
}
}
func (m Money) IsZero() bool {
return m.amount.IsZero()
}
// 创建Money的构造函数
func NewMoney(amount float64, currency string) Money {
return Money{
amount: decimal.NewFromFloat(amount),
currency: currency,
}
}
// 地址值对象
type Address struct {
street string
city string
zipCode string
country string
}
func (a Address) IsValid() bool {
return a.street != "" && a.city != "" && a.zipCode != ""
}
3.3 聚合(Aggregate)
定义:
一组相关对象的集合,作为数据修改的单元
// 类型定义
type ProductID string
type OrderID string
type CustomerID string
type OrderStatus string
const (
OrderStatusDraft OrderStatus = "DRAFT"
OrderStatusConfirmed OrderStatus = "CONFIRMED"
OrderStatusShipped OrderStatus = "SHIPPED"
)
// 错误定义
var (
ErrOrderNotEditable = errors.New("订单不可编辑")
ErrProductNotFound = errors.New("商品不存在")
)
// 订单项 - 聚合内部实体
type OrderItem struct {
ProductID ProductID // 商品ID
Quantity int // 数量
UnitPrice Money // 单价
Subtotal Money // 小计
}
// 订单聚合 - Order是聚合根
type Order struct {
id OrderID
customerID CustomerID
items []OrderItem // 聚合内部对象
address Address // 值对象
status OrderStatus
totalAmount Money
}
// 聚合根控制内部对象的访问
func (o *Order) ChangeQuantity(productID ProductID, newQuantity int) error {
if o.status != OrderStatusDraft {
return ErrOrderNotEditable
}
for i, item := range o.items {
if item.ProductID == productID {
if newQuantity <= 0 {
// 删除商品项
o.items = append(o.items[:i], o.items[i+1:]...)
} else {
// 更新数量
o.items[i].Quantity = newQuantity
o.items[i].Subtotal = item.UnitPrice.Multiply(newQuantity)
}
o.recalculateTotal() // 保证聚合内部一致性
return nil
}
}
return ErrProductNotFound
}
// 私有方法 - 重新计算总金额
func (o *Order) recalculateTotal() {
var total Money
for _, item := range o.items {
total = total.Add(item.Subtotal)
}
o.totalAmount = total
}
3.4 领域服务(Domain Service)
定义:
不属于任何实体或值对象的业务逻辑
// 订单定价服务 - 复杂的定价逻辑
type OrderPricingService struct{}
func (s *OrderPricingService) CalculateDiscount(order *Order, customer *Customer) Money {
var discount Money
// VIP客户折扣
if customer.IsVIP() {
discount = order.TotalAmount().Multiply(0.1)
}
// 满减优惠
if order.TotalAmount().GreaterThan(NewMoney(100, "CNY")) {
fullReductionDiscount := NewMoney(20, "CNY")
if fullReductionDiscount.GreaterThan(discount) {
discount = fullReductionDiscount
}
}
return discount
}
3.5 仓储(Repository)
定义:
封装数据访问逻辑的接口
// 领域层定义接口
type OrderRepository interface {
Save(order *Order) error
FindByID(id OrderID) (*Order, error)
FindByCustomer(customerID CustomerID) ([]*Order, error)
}
// 基础设施层实现接口
type PostgreSQLOrderRepository struct {
db *sql.DB
}
func (r *PostgreSQLOrderRepository) Save(order *Order) error {
// 数据库持久化逻辑
return r.db.Exec("INSERT INTO orders ...")
}
第四章:DDD分层架构
DDD推荐使用四层架构:

internal/
├── interfaces/ # 接口层 - 外部交互
│ └── http/
│ ├── handler/ # HTTP处理器
│ └── middleware/ # 中间件
├── application/ # 应用层 - 业务流程编排
│ ├── service/ # 应用服务
│ └── dto/ # 数据传输对象
├── domain/ # 领域层 - 核心业务逻辑
│ ├── entity/ # 领域实体
│ ├── repository/ # 仓储接口
│ └── valueobj/ # 值对象
└── infrastructure/ # 基础设施层 - 技术实现
├── persistence/ # 数据持久化
│ ├── postgres/ # PostgreSQL实现
│ └── bytehouse/ # ByteHouse实现
└── provider/ # 外部服务提供者
gRPC 是一种远程调用框架,CLI (Command Line Interface)是命令行界面
gRPC 是谷歌开源的高性能远程过程调用(RPC)框架,可以简单理解为:
- 你在 A 服务器写了一个函数,B 服务器可以像调用本地函数一样调用它(跨服务器 / 跨语言)
- 基于 HTTP/2 协议,用 Protocol Buffers(PB)做数据序列化(比 JSON 更高效、体积更小)
- 常见于微服务之间的通信(比如 DDD 架构中不同域的服务调用)
4.1 各层职责
Interface Layer(接口层)
// HTTP控制器
type OrderController struct {
orderService *application.OrderService
}
func (c *OrderController) CreateOrder(w http.ResponseWriter, r *http.Request) {
var req CreateOrderRequest
json.NewDecoder(r.Body).Decode(&req)
// 转换为应用层命令
cmd := application.CreateOrderCommand{
CustomerID: req.CustomerID,
Items: req.Items,
}
result, err := c.orderService.CreateOrder(cmd)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
json.NewEncoder(w).Encode(result)
}
Application Layer(应用层)
type OrderService struct {
orderRepo domain.OrderRepository
customerRepo domain.CustomerRepository
pricingService *domain.OrderPricingService
}
func (s *OrderService) CreateOrder(cmd CreateOrderCommand) (*OrderDTO, error) {
// 1. 输入验证
if err := cmd.Validate(); err != nil {
return nil, err
}
// 2. 加载领域对象
customer, err := s.customerRepo.FindByID(cmd.CustomerID)
if err != nil {
return nil, err
}
// 3. 执行业务逻辑
order := domain.NewOrder(customer.ID(), cmd.Items)
discount := s.pricingService.CalculateDiscount(order, customer)
order.ApplyDiscount(discount)
// 4. 持久化
if err := s.orderRepo.Save(order); err != nil {
return nil, err
}
// 5. 返回结果
return s.toDTO(order), nil
}
Domain Layer(领域层)
// 纯业务逻辑,不依赖外部技术
type Order struct {
id OrderID
customerID CustomerID
items []OrderItem
status OrderStatus
totalAmount Money
}
func (o *Order) ApplyDiscount(discount Money) error {
if discount.GreaterThan(o.totalAmount) {
return ErrDiscountTooLarge
}
o.totalAmount = o.totalAmount.Subtract(discount)
return nil
}
Infrastructure Layer(基础设施层)
/ 技术实现,可替换
type PostgreSQLOrderRepository struct {
db *sql.DB
}
func (r *PostgreSQLOrderRepository) Save(order *domain.Order) error {
// 具体的数据库操作
return r.db.Exec("INSERT INTO orders ...")
}
第五章:实战项目解析
现在让我们看看在真实项目中是如何应用DDD的。以我们的商品分析项目为例:
5.1 业务背景
我们要构建一个AI驱动的商品合规性分析系统:
- 输入:商品信息、素材数据、投诉数据
- 处理:通过AI大模型分析商品是否违规
- 输出:风险等级、违规类型、违规原因
5.2 领域建模
核心领域:商品合规性分析
支撑领域:素材管理、投诉处理
通用领域:AI服务调用、数据存储
限界上下文划分:
商品分析系统
├── 商品上下文(Goods Context)
│ ├── 商品实体(Spu)
│ ├── 商品类型(SpuType)
│ └── 销售状态(SaleStatus)
├── 分析上下文(Analysis Context)
│ ├── 分析结果(GoodsAnalysisResult)
│ ├── 风险等级(RiskLevel)
│ └── 违规类型(ViolationType)
└── AI上下文(AI Context)
├── 提示词(Prompt)
├── AI请求(ChatRequest)
└── AI响应(ChatResponse)
5.3 核心领域对象
分析结果实体
// 分析结果实体 - 有唯一标识,状态可变
type GoodsAnalysisResult struct {
id int64 // 唯一标识
spuID string // 商品ID
appID string // 店铺ID
goodsName string // 商品名称
riskLevel string // 风险等级
violationType string // 违规类型
violationReason string // 违规原因
nonce string // 幂等性标识
createdAt time.Time
updatedAt time.Time
}
// 业务行为 - 标准化违规类型
func (r *GoodsAnalysisResult) NormalizeViolationType() {
r.violationType = normalizeViolationType(r.violationType)
}
// 业务查询 - 是否高风险
func (r *GoodsAnalysisResult) IsHighRisk() bool {
return r.riskLevel == string(RiskLevelSerious)
}
风险等级值对象
// 风险等级值对象 - 不可变,通过值区分
type RiskLevel string
const (
RiskLevelNoRisk RiskLevel = "无风险"
RiskLevelLight RiskLevel = "轻度风险"
RiskLevelMedium RiskLevel = "中度风险"
RiskLevelSerious RiskLevel = "严重风险"
)
func (r RiskLevel) IsValid() bool {
switch r {
case RiskLevelNoRisk, RiskLevelLight, RiskLevelMedium, RiskLevelSerious:
return true
default:
return false
}
}
func (r RiskLevel) IsSeriousOrAbove() bool {
return r == RiskLevelSerious
}
5.4 应用服务实现
// 应用服务 - 编排业务流程
type GoodsAnalyzeService struct {
// 依赖仓储接口,不依赖具体实现
spuRepo repository.SpuRepo
materialRepo repository.MaterialRepo
resultRepo repository.GoodsAnalysisRepo
metaRouterService *MetaRouterService // AI服务
}
// 核心业务流程
func (s *GoodsAnalyzeService) Analyze(ctx context.Context, req *dto.GoodsAnalyzeRequest) (*dto.GoodsAnalyzeResponse, error) {
// 1. 参数验证
if err := req.Validate(); err != nil {
return nil, err
}
// 2. 加载Prompt(AI提示词)
prompt, err := s.loadPrompt(ctx, req.WithComplaint)
if err != nil {
return nil, err
}
// 3. 使用工作流引擎执行分析
return s.executeAnalysisWorkflow(ctx, req, prompt)
}
// 工作流执行 - 拆解复杂流程
func (s *GoodsAnalyzeService) executeAnalysisWorkflow(
ctx context.Context,
req *dto.GoodsAnalyzeRequest,
prompt *entity.PromptEntity,
) (*dto.GoodsAnalyzeResponse, error) {
// 创建工作流模板
tmpl := workflow.NewTemplate()
// 定义工作流节点
tmpl.Add(workflow.NewAgent("load_goods", s.loadGoodsAgent))
tmpl.Add(workflow.NewAgent("load_materials", s.loadMaterialsAgent),
workflow.WithDependsOn("load_goods"))
tmpl.Add(workflow.NewAgent("ai_analyze", s.aiAnalyzeAgent),
workflow.WithDependsOn("load_materials"))
tmpl.Add(workflow.NewAgent("save_results", s.saveResultsAgent),
workflow.WithDependsOn("ai_analyze"))
// 执行工作流
wf := tmpl.Instantiate()
if err := wf.Start(ctx); err != nil {
return nil, err
}
// 获取结果
result, err := workflow.Get[*dto.GoodsAnalyzeResponse](wf.GetStore(), "response")
return result, err
}
5.5 基础设施层实现
仓储实现
// PostgreSQL仓储实现
type GoodsAnalysisRepoImpl struct {
db *gorm.DB
}
// 实现领域层定义的接口
func (r *GoodsAnalysisRepoImpl) Upsert(ctx context.Context, results []*entity.GoodsAnalysisResult) error {
if len(results) == 0 {
return nil
}
// 转换为持久化对象
pos := r.toPOs(results)
// 使用数据库的UPSERT功能保证幂等性
err := r.db.WithContext(ctx).Clauses(clause.OnConflict{
Columns: []clause.Column{
{Name: "app_id"},
{Name: "spu_id"},
{Name: "nonce"}, // 幂等性标识
},
DoUpdates: clause.AssignmentColumns([]string{
"goods_name", "risk_level", "violation_type",
"violation_reason", "updated_at",
}),
}).Create(&pos).Error
if err != nil {
return fmt.Errorf("保存分析结果失败: %w", err)
}
return nil
}
// 对象映射 - 领域对象转持久化对象
func (r *GoodsAnalysisRepoImpl) toPO(e *entity.GoodsAnalysisResult) *goodsAnalysisRepoPO {
var po goodsAnalysisRepoPO
_ = copier.Copy(&po, e) // 使用copier库简化拷贝
// 处理特殊字段
po.CreatedAt = time.Now()
po.UpdatedAt = time.Now()
return &po
}
AI服务集成
// AI网关服务 - 防腐层模式
type MetaRouterService struct {
baseURL string
apiKey string
}
func (s *MetaRouterService) CallChatCompletions(
ctx context.Context,
req *dto.MetaRouterChatRequest,
appID string,
) (*dto.MetaRouterChatResponse, error) {
url := s.baseURL + "/api/v1/chat/completions"
var resp dto.MetaRouterChatResponse
err := http.Post(url).
Header("Authorization", "Bearer "+s.apiKey).
Header("X-App-ID", appID). // 灰度发布支持
Json(req).
SendForJson(ctx, &resp)
if err != nil {
return nil, fmt.Errorf("AI调用失败: %w", err)
}
return &resp, nil
}
第六章:DDD的优势与挑战
6.1 优势
- 业务逻辑集中在领域对象内部,符合面向对象原则
- 代码即文档,业务规则清晰可见
- 降低了业务逻辑分散的风险
1. 业务表达力强
// 代码直接反映业务概念
func (order *Order) CanBeCancelled() bool {
return order.status == OrderStatusPending ||
order.status == OrderStatusConfirmed
}
// 业务专家看到这样的代码也能理解
if order.CanBeCancelled() {
order.Cancel()
}
2. 可维护性高
- 业务逻辑集中在领域对象中
- 修改业务规则时,影响范围可控
- 代码结构清晰,易于理解
3. 可测试性好
func TestOrder_CanBeCancelled(t *testing.T) {
// Given
order := NewOrder("customer-001")
order.Confirm()
// When & Then
assert.True(t, order.CanBeCancelled())
// When
order.Ship()
// Then
assert.False(t, order.CanBeCancelled())
}
4. 团队协作效率高
- 建立了通用语言
- 技术人员和业务专家能够无障碍沟通
- 代码即文档,减少了文档维护成本
6.2 挑战
1. 学习曲线陡峭
- 需要理解大量的概念和模式
- 需要改变传统的编程思维
2. 过度设计的风险
// ❌ 过度抽象的例子
type AbstractOrderProcessor interface {
ProcessOrder(order Order, context ProcessingContext) ProcessingResult
}
// ✅ 简单直接的例子
type OrderService struct {
orderRepo OrderRepository
}
func (s *OrderService) ProcessOrder(order *Order) error {
return s.orderRepo.Save(order)
}
3. 性能考虑
- 富领域模型可能带来性能开销
- 需要在业务表达力和性能之间找到平衡
总结
DDD的核心不在于技术,而在于思维方式的转变:
从技术驱动转向业务驱动
从数据建模转向行为建模
从代码实现转向问题解决
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)