📌 重要提示:Application 层是高级扩展,仅在需要跨领域编排时才添加。
单领域操作不需要 Application 层,直接在 Handler 中调用 Repository 即可。
Application 层(应用层)负责编排多个领域之间的交互,实现跨领域的业务流程。
- ✅ 编排领域服务:协调多个领域完成复杂业务流程
- ✅ 事务管理:管理跨领域的事务边界
- ✅ 适配外部接口:将 HTTP 请求适配到领域操作
- ✅ 数据组合:组合多个领域的数据返回给客户端
- ❌ 业务逻辑实现(属于 Domain Layer)
- ❌ 技术基础设施(属于 Infrastructure Layer)
- ❌ HTTP 路由和中间件(属于 HTTP Layer)
场景:只涉及一个领域的操作
// ❌ 不需要 Application 层
// domains/task/handlers/create_task.handler.go
func CreateTaskHandler(service *HandlerService) app.HandlerFunc {
return func(ctx context.Context, c *app.RequestContext) {
// 直接调用 Repository
task, err := service.taskRepo.Create(ctx, ...)
c.JSON(200, task)
}
}特点:
- 只操作 Task 领域
- 不涉及其他领域
- 业务逻辑简单清晰
场景 1:创建任务并发送通知
涉及领域:
- Task 领域:创建任务
- User 领域:获取用户信息
- Notification 领域:发送通知
// ✅ 需要 Application 层编排
// application/services/task_orchestrator.go
type TaskOrchestrator struct {
taskRepo repository.TaskRepository // Task 领域
userService *user.Service // User 领域
notifyService *notification.Service // Notification 领域
}
func (o *TaskOrchestrator) CreateTaskWithNotification(ctx context.Context, req *CreateTaskRequest) error {
// 1. Task Domain: 创建任务
task, err := o.taskRepo.Create(ctx, ...)
if err != nil {
return err
}
// 2. User Domain: 获取用户信息
user, err := o.userService.GetUser(ctx, req.UserID)
if err != nil {
return err
}
// 3. Notification Domain: 发送通知
err = o.notifyService.Send(ctx, ¬ification.SendRequest{
UserID: user.ID,
Email: user.Email,
Subject: "新任务已创建",
Body: fmt.Sprintf("任务 '%s' 已创建", task.Title),
})
if err != nil {
// 记录日志但不中断
log.Printf("Failed to send notification: %v", err)
}
return nil
}场景 2:订单支付流程
涉及领域:
- Order 领域:创建订单
- Inventory 领域:扣减库存
- Payment 领域:处理支付
- Notification 领域:发送确认邮件
// application/services/order_orchestrator.go
func (o *OrderOrchestrator) PlaceOrder(ctx context.Context, req *PlaceOrderRequest) (*PlaceOrderResponse, error) {
// 1. Order: 创建订单
order, err := o.orderRepo.Create(ctx, ...)
// 2. Inventory: 扣减库存(带补偿)
err = o.inventoryService.Reserve(ctx, order.Items)
if err != nil {
// 补偿:取消订单
o.orderRepo.Cancel(ctx, order.ID)
return nil, err
}
// 3. Payment: 处理支付(带补偿)
payment, err := o.paymentService.Charge(ctx, order.TotalAmount)
if err != nil {
// 补偿:释放库存 + 取消订单
o.inventoryService.Release(ctx, order.Items)
o.orderRepo.Cancel(ctx, order.ID)
return nil, err
}
// 4. Notification: 发送确认邮件
o.notificationService.Send(ctx, ...)
return &PlaceOrderResponse{OrderID: order.ID}, nil
}mkdir -p backend/application/services
mkdir -p backend/application/dto目录结构:
backend/application/
├── services/ # 应用服务(编排多个领域)
│ ├── task_orchestrator.go
│ └── order_orchestrator.go
├── dto/ # 应用层 DTO(可能组合多个领域)
│ └── orchestration.go
└── README.md
// application/services/task_orchestrator.go
package services
import (
"context"
taskrepo "github.com/erweixin/go-genai-stack/domains/task/repository"
userservice "github.com/erweixin/go-genai-stack/domains/user"
notifyservice "github.com/erweixin/go-genai-stack/domains/notification"
)
// TaskOrchestrator 任务编排服务
//
// 职责:编排 Task、User、Notification 三个领域
type TaskOrchestrator struct {
taskRepo taskrepo.TaskRepository
userService *userservice.Service
notifyService *notifyservice.Service
}
// NewTaskOrchestrator 创建任务编排服务
func NewTaskOrchestrator(
taskRepo taskrepo.TaskRepository,
userService *userservice.Service,
notifyService *notifyservice.Service,
) *TaskOrchestrator {
return &TaskOrchestrator{
taskRepo: taskRepo,
userService: userService,
notifyService: notifyService,
}
}
// CreateTaskWithNotification 创建任务并发送通知
//
// 编排流程:
// 1. 创建任务(Task Domain)
// 2. 获取用户信息(User Domain)
// 3. 发送通知(Notification Domain)
func (o *TaskOrchestrator) CreateTaskWithNotification(
ctx context.Context,
req *CreateTaskWithNotificationRequest,
) (*CreateTaskWithNotificationResponse, error) {
// 实现编排逻辑
// ...
}// domains/task/handlers/create_task_with_notification.handler.go
package handlers
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/erweixin/go-genai-stack/application/services"
)
// CreateTaskWithNotificationHandler 创建任务并发送通知
//
// 这是一个跨领域操作,需要调用 Application 层的编排服务
func CreateTaskWithNotificationHandler(orchestrator *services.TaskOrchestrator) app.HandlerFunc {
return func(ctx context.Context, c *app.RequestContext) {
var req dto.CreateTaskWithNotificationRequest
if err := c.BindAndValidate(&req); err != nil {
c.JSON(400, map[string]interface{}{"error": err.Error()})
return
}
// 调用 Application 层编排服务
resp, err := orchestrator.CreateTaskWithNotification(ctx, &req)
if err != nil {
c.JSON(500, map[string]interface{}{"error": err.Error()})
return
}
c.JSON(200, resp)
}
}在 infrastructure/bootstrap/dependencies.go 中注入:
// InitDependencies 初始化应用依赖
func InitDependencies(
dbConn *postgres.Connection,
redisConn *redis.Connection,
) *AppContainer {
db := dbConn.DB()
// 1. 初始化各领域 Repository
taskRepo := taskrepo.NewTaskRepository(db)
userRepo := userrepo.NewUserRepository(db)
// 2. 初始化各领域 Service
userService := userservice.NewService(userRepo)
notifyService := notifyservice.NewService(redisConn)
// 3. 初始化 Application 层编排服务
taskOrchestrator := appservices.NewTaskOrchestrator(
taskRepo,
userService,
notifyService,
)
return &AppContainer{
TaskOrchestrator: taskOrchestrator,
}
}-
编排,不实现
- Application 层只编排,不实现业务逻辑
- 业务规则放在领域层
-
事务边界
- 在 Application 层管理跨领域事务
- 使用 Saga 模式处理分布式事务
-
薄层原则
- Application 层应该保持简单
- 复杂逻辑放在领域层
-
依赖注入
- 通过构造函数注入领域服务
- 不要在 Application 层创建领域对象
-
不要在 Application 层实现业务规则
// ❌ 错误:业务规则在 Application 层 func (o *TaskOrchestrator) CreateTask(...) { if task.Priority == "high" && task.DueDate < time.Now() { // 这是业务规则,应该在 Domain Layer } } // ✅ 正确:业务规则在 Domain Layer // domains/task/model/task.go func (t *Task) Validate() error { if t.Priority == "high" && t.DueDate.Before(time.Now()) { return errors.New("high priority task cannot have past due date") } return nil }
-
不要直接访问数据库
// ❌ 错误:直接访问数据库 func (o *TaskOrchestrator) CreateTask(...) { o.db.Exec("INSERT INTO tasks ...") } // ✅ 正确:通过领域的仓储接口 func (o *TaskOrchestrator) CreateTask(...) { o.taskRepo.Create(...) }
-
不要跨领域直接调用
// ❌ 错误:跨领域直接调用 func (o *TaskOrchestrator) CreateTask(...) { // 直接调用另一个领域的 Repository user := o.userRepo.FindByID(...) } // ✅ 正确:通过领域的 Service func (o *TaskOrchestrator) CreateTask(...) { user := o.userService.GetUser(...) }
// application/services/task_orchestrator_test.go
package services
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// MockTaskRepository Mock 实现
type MockTaskRepository struct {
mock.Mock
}
func (m *MockTaskRepository) Create(ctx context.Context, task *model.Task) error {
args := m.Called(ctx, task)
return args.Error(0)
}
// MockUserService Mock 实现
type MockUserService struct {
mock.Mock
}
func (m *MockUserService) GetUser(ctx context.Context, userID string) (*user.User, error) {
args := m.Called(ctx, userID)
return args.Get(0).(*user.User), args.Error(1)
}
func TestTaskOrchestrator_CreateTaskWithNotification(t *testing.T) {
// Arrange
mockTaskRepo := new(MockTaskRepository)
mockUserService := new(MockUserService)
mockNotifyService := new(MockNotifyService)
orchestrator := NewTaskOrchestrator(mockTaskRepo, mockUserService, mockNotifyService)
// Mock 期望
mockTaskRepo.On("Create", mock.Anything, mock.Anything).Return(nil)
mockUserService.On("GetUser", mock.Anything, "user-123").Return(&user.User{
ID: "user-123",
Email: "test@example.com",
}, nil)
mockNotifyService.On("Send", mock.Anything, mock.Anything).Return(nil)
// Act
resp, err := orchestrator.CreateTaskWithNotification(ctx, &CreateTaskWithNotificationRequest{
UserID: "user-123",
Title: "Test Task",
})
// Assert
assert.NoError(t, err)
assert.NotNil(t, resp)
// 验证所有领域服务都被调用
mockTaskRepo.AssertExpectations(t)
mockUserService.AssertExpectations(t)
mockNotifyService.AssertExpectations(t)
}// application/services/order_orchestrator.go
package services
import (
"context"
"fmt"
orderrepo "github.com/erweixin/go-genai-stack/domains/order/repository"
inventoryservice "github.com/erweixin/go-genai-stack/domains/inventory"
paymentservice "github.com/erweixin/go-genai-stack/domains/payment"
notificationservice "github.com/erweixin/go-genai-stack/domains/notification"
)
type OrderOrchestrator struct {
orderRepo orderrepo.OrderRepository
inventoryService *inventoryservice.Service
paymentService *paymentservice.Service
notifyService *notificationservice.Service
}
func (o *OrderOrchestrator) PlaceOrder(ctx context.Context, req *PlaceOrderRequest) (*PlaceOrderResponse, error) {
// 步骤 1: 创建订单(Order Domain)
order, err := o.orderRepo.Create(ctx, &order.Order{
UserID: req.UserID,
Items: req.Items,
TotalAmount: req.TotalAmount,
})
if err != nil {
return nil, fmt.Errorf("failed to create order: %w", err)
}
// 步骤 2: 扣减库存(Inventory Domain)
err = o.inventoryService.Reserve(ctx, &inventory.ReserveRequest{
OrderID: order.ID,
Items: order.Items,
})
if err != nil {
// 补偿:取消订单
_ = o.orderRepo.Cancel(ctx, order.ID)
return nil, fmt.Errorf("failed to reserve inventory: %w", err)
}
// 步骤 3: 处理支付(Payment Domain)
payment, err := o.paymentService.Charge(ctx, &payment.ChargeRequest{
OrderID: order.ID,
Amount: order.TotalAmount,
Method: req.PaymentMethod,
})
if err != nil {
// 补偿:释放库存 + 取消订单
_ = o.inventoryService.Release(ctx, order.ID)
_ = o.orderRepo.Cancel(ctx, order.ID)
return nil, fmt.Errorf("failed to charge payment: %w", err)
}
// 步骤 4: 更新订单状态(Order Domain)
err = o.orderRepo.UpdateStatus(ctx, order.ID, "paid")
if err != nil {
// 这里已经扣款成功,不能轻易回滚,需要人工介入
// 记录错误日志,触发告警
return nil, fmt.Errorf("failed to update order status: %w", err)
}
// 步骤 5: 发送确认邮件(Notification Domain)
// 这是非关键步骤,失败不影响主流程
_ = o.notifyService.Send(ctx, ¬ification.SendRequest{
UserID: order.UserID,
Type: "order_confirmation",
Subject: "订单确认",
Body: fmt.Sprintf("您的订单 %s 已确认", order.ID),
})
return &PlaceOrderResponse{
OrderID: order.ID,
PaymentID: payment.ID,
Status: "paid",
}, nil
}| 场景 | 是否需要 Application 层 |
|---|---|
| 单领域 CRUD 操作 | ❌ 不需要(直接在 Handler 中调用 Repository) |
| 单领域业务逻辑 | ❌ 不需要(业务逻辑在 Domain Layer) |
| 跨领域编排 | ✅ 需要(Application 层协调多个领域) |
| 分布式事务 | ✅ 需要(Application 层管理事务边界和补偿) |
| 复杂工作流 | ✅ 需要(Application 层编排多个步骤) |
- 🎯 Application 层是高级扩展,不是必需的
- 🎯 保持简单,只在真正需要时才添加
- 🎯 编排而非实现,业务逻辑放在领域层
Happy Coding! 🚀