113 lines
3.5 KiB
Markdown
113 lines
3.5 KiB
Markdown
# 模块四层模式
|
||
|
||
每个业务模块内部采用四层结构:**Domain → Application → Infrastructure → Interfaces**。
|
||
|
||
## 四层结构
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ Interfaces │ ← HTTP Handler, 路由注册
|
||
├─────────────────────────────────────┤
|
||
│ Application │ ← 业务逻辑编排
|
||
├─────────────────────────────────────┤
|
||
│ Infrastructure │ ← GORM Model, Redis 实现
|
||
├─────────────────────────────────────┤
|
||
│ Domain │ ← 实体, 值对象, 接口定义
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
## 依赖方向
|
||
|
||
**从上到下依赖,Domain 在最底层,不依赖任何外部包。**
|
||
|
||
| 层 | 职责 | 可以依赖 | 禁止依赖 |
|
||
|---|---|---|---|
|
||
| Interfaces | HTTP 入口 | Application, Domain | Infrastructure |
|
||
| Application | 业务编排 | Domain | Infrastructure, Interfaces |
|
||
| Infrastructure | 数据持久化 | Domain | Application, Interfaces |
|
||
| Domain | 业务核心 | 标准库 | 所有外部包 |
|
||
|
||
## Domain 层
|
||
|
||
定义业务的核心概念和契约:
|
||
|
||
```go
|
||
// domain/entity.go
|
||
type User struct {
|
||
ID uint
|
||
Email string
|
||
Username string
|
||
Password string
|
||
TenantID string
|
||
}
|
||
|
||
// domain/repository.go — 定义接口,不定义实现
|
||
type UserRepository interface {
|
||
Create(ctx context.Context, user *User) error
|
||
FindByEmail(ctx context.Context, email string) (*User, error)
|
||
}
|
||
```
|
||
|
||
Domain 层**零外部依赖**,只使用 Go 标准库。这使得业务逻辑可以独立于框架和数据库进行单元测试。
|
||
|
||
## Application 层
|
||
|
||
编排业务流程,调用 Domain 层定义的接口:
|
||
|
||
```go
|
||
// application/service.go
|
||
type Service struct {
|
||
repo domain.UserRepository
|
||
hasher domain.PasswordHasher
|
||
jwt domain.TokenManager
|
||
}
|
||
|
||
func (s *Service) Register(ctx context.Context, req domain.RegisterRequest) (*domain.TokenPair, error) {
|
||
// 1. 验证邮箱唯一性
|
||
// 2. 密码哈希
|
||
// 3. 创建用户
|
||
// 4. 生成 JWT
|
||
// 5. 返回 Token
|
||
}
|
||
```
|
||
|
||
Application 层不知道数据是怎么存的(GORM?Redis?),它只依赖 Domain 层定义的接口。
|
||
|
||
## Infrastructure 层
|
||
|
||
提供 Domain 层接口的具体实现:
|
||
|
||
```go
|
||
// infrastructure/repository.go
|
||
type GormUserRepository struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
func (r *GormUserRepository) Create(ctx context.Context, user *domain.User) error {
|
||
// GORM 实现
|
||
}
|
||
```
|
||
|
||
Infrastructure 层实现 Domain 层定义的接口,但 Domain 层不知道 Infrastructure 的存在。
|
||
|
||
## Interfaces 层
|
||
|
||
HTTP 入口,负责请求解析和响应:
|
||
|
||
```go
|
||
// interfaces/handler.go
|
||
func (h *Handler) Register(c *gin.Context) {
|
||
var req domain.RegisterRequest
|
||
c.ShouldBindJSON(&req)
|
||
tokens, err := h.svc.Register(c.Request.Context(), req)
|
||
response.Success(c, tokens)
|
||
}
|
||
```
|
||
|
||
## 好处
|
||
|
||
1. **可测试**:Domain 层可以脱离数据库进行单元测试
|
||
2. **可替换**:换数据库只需写新的 Infrastructure 实现
|
||
3. **边界清晰**:每层职责明确,新人容易理解
|
||
4. **防止腐败**:Gin 的 `c *gin.Context` 不会渗透到业务逻辑中
|