我来详细讲解领域驱动设计(DDD)在Go语言中的应用。Go语言的特点是简洁、并发性强,在实现DDD时也有其独特的实践方式。
// domain/order.go
package domain
import (
"time"
"errors"
)
// 值对象
type Money struct {
Amount float64
Currency string
}
// 实体
type Order struct {
ID string
CustomerID string
Items []OrderItem
TotalAmount Money
Status OrderStatus
CreatedAt time.Time
}
// 值对象
type OrderItem struct {
ProductID string
Quantity int
Price Money
}
type OrderStatus string
const (
OrderStatusPending OrderStatus = "pending"
OrderStatusPaid OrderStatus = "paid"
OrderStatusShipped OrderStatus = "shipped"
)
// 领域方法
func NewOrder(customerID string, items []OrderItem) (*Order, error) {
if len(items) == 0 {
return nil, errors.New("order must have at least one item")
}
totalAmount := calculateTotalAmount(items)
return &Order{
ID: generateID(),
CustomerID: customerID,
Items: items,
TotalAmount: totalAmount,
Status: OrderStatusPending,
CreatedAt: time.Now(),
}, nil
}
func (o *Order) Pay() error {
if o.Status != OrderStatusPending {
return errors.New("order must be in pending status to pay")
}
o.Status = OrderStatusPaid
return nil
}
// repository/order.go
package repository
type OrderRepository interface {
Save(order *domain.Order) error
FindByID(id string) (*domain.Order, error)
Update(order *domain.Order) error
}
// 具体实现
type PostgresOrderRepository struct {
db *sql.DB
}
func (r *PostgresOrderRepository) Save(order *domain.Order) error {
// 实现保存逻辑
return nil
}
// application/order_service.go
package application
type OrderService struct {
orderRepo repository.OrderRepository
eventBus event.EventBus
}
func (s *OrderService) CreateOrder(cmd CreateOrderCommand) (*domain.Order, error) {
order, err := domain.NewOrder(cmd.CustomerID, cmd.Items)
if err != nil {
return nil, err
}
if err := s.orderRepo.Save(order); err != nil {
return nil, err
}
s.eventBus.Publish(NewOrderCreatedEvent(order))
return order, nil
}
// infrastructure/event/event_bus.go
package event
type EventBus interface {
Publish(event interface{}) error
Subscribe(handler EventHandler)
}
type OrderCreatedEvent struct {
OrderID string
CustomerID string
CreatedAt time.Time
}
// interfaces/http/handler.go
package http
type OrderHandler struct {
orderService *application.OrderService
}
func (h *OrderHandler) CreateOrder(w http.ResponseWriter, r *http.Request) {
var cmd CreateOrderCommand
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
order, err := h.orderService.CreateOrder(cmd)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(order)
}
以上代码展示了Go语言中DDD的主要实现方式,让我解释几个关键点:
1、领域层设计特点:
- 使用结构体表示实体和值对象
- 通过方法实现领域逻辑
- 使用接口定义仓储和服务契约
- 领域事件的发布和订阅
2、Go语言特有的DDD实践:
- 利用接口进行依赖反转
- 使用组合而非继承
- 错误处理遵循Go惯例
- 并发处理采用channel和goroutine
3、分层架构的实现:
- domain: 领域模型和业务规则
- application: 应用服务层,协调领域对象
- infrastructure: 技术实现细节
- interfaces: 用户界面和外部接口
4、关键实践建议:
// 1. 使用接口定义契约
type Repository interface {
Save(entity Entity) error
FindByID(id string) (Entity, error)
}
// 2. 值对象实现
type Address struct {
Street string
City string
Country string
}
// 3. 领域服务
type DomainService struct {
repo Repository
}
// 4. 工厂方法
func NewEntity(params ...interface{}) (*Entity, error) {
// 验证和创建逻辑
}
5、Go语言DDD的最佳实践:
- 使用interface来定义仓储和服务的契约
- 领域对象应该是不可变的
- 使用值对象来封装相关的属性
- 利用Go的struct tag来处理持久化
- 使用context来处理请求上下文
- 错误处理遵循Go的错误处理惯例
你是否想了解更具体的某个部分?比如: