9.8 KiB
9.8 KiB
Domain 域概念详解
🤔 什么是 Domain(域)?
Domain(域) 就像现实世界中的部门或业务范围。
📚 现实世界的类比
想象一个大公司:
阿里巴巴集团
├── 电商域 (淘宝、天猫)
├── 支付域 (支付宝)
├── 云计算域 (阿里云)
├── 物流域 (菜鸟)
└── 金融域 (蚂蚁金服)
每个域都有:
- 专门的团队 - 不同的开发团队
- 独立的业务 - 各自负责不同的业务功能
- 清晰的边界 - 知道自己管什么,不管什么
- 独立运作 - 可以独立决策和发展
🏗️ 在软件架构中的应用
传统方式 vs 域驱动方式
❌ 传统方式(技术驱动)
项目结构:
├── controllers/ # 所有控制器
├── services/ # 所有服务
├── models/ # 所有数据模型
└── utils/ # 工具类
问题:
- 用户相关、产品相关、支付相关的代码混在一起
- 不同业务逻辑耦合
- 团队协作困难
- 修改一个功能可能影响其他功能
✅ 域驱动方式(业务驱动)
项目结构:
├── user-domain/ # 用户域
│ ├── user/ # 用户管理
│ ├── auth/ # 认证授权
│ └── profile/ # 用户资料
├── product-domain/ # 产品域
│ ├── catalog/ # 产品目录
│ ├── inventory/ # 库存管理
│ └── pricing/ # 价格管理
├── payment-domain/ # 支付域
│ ├── wallet/ # 钱包
│ ├── order/ # 订单
│ └── billing/ # 计费
└── notification-domain/ # 通知域
├── email/ # 邮件通知
├── sms/ # 短信通知
└── push/ # 推送通知
优势:
- 按业务功能组织代码
- 团队可以独立开发不同的域
- 修改用户功能不会影响支付功能
- 新人容易理解业务边界
🎯 你的项目中的 Domain 重构
当前问题
你的项目中有这些编码式命名:
IVYZ - 不知道是什么业务
FLXG - 不知道是什么业务
QYGL - 不知道是什么业务
YYSY - 不知道是什么业务
JRZQ - 不知道是什么业务
重构后的 Domain 设计
用户域 (User Domain)
├── 用户注册登录
├── 用户信息管理
├── 企业认证
└── 权限管理
金融域 (Financial Domain)
├── 钱包管理
├── 支付处理
├── 账单生成
└── 财务报表
数据服务域 (Data Service Domain)
├── 风险评估服务 (原 FLXG)
├── 征信查询服务 (原 JRZQ)
├── 企业信息服务 (原 QYGL)
├── 数据查询服务 (原 IVYZ)
└── 应用系统服务 (原 YYSY)
产品域 (Product Domain)
├── 产品目录管理
├── 产品订阅
├── 访问控制
└── 白名单管理
平台域 (Platform Domain)
├── 管理后台
├── 系统监控
├── 日志管理
└── 配置管理
💻 代码层面的 Domain 实现
1. Domain 层的职责
// domain/user/entity/user.go
package entity
import (
"errors"
"time"
)
// User 用户实体
type User struct {
ID int64 `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Phone string `json:"phone"`
Status UserStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type UserStatus int
const (
UserStatusActive UserStatus = 1
UserStatusInactive UserStatus = 2
UserStatusBanned UserStatus = 3
)
// 业务规则:用户名必须是3-20个字符
func (u *User) ValidateUsername() error {
if len(u.Username) < 3 || len(u.Username) > 20 {
return errors.New("用户名必须是3-20个字符")
}
return nil
}
// 业务规则:检查用户是否可以登录
func (u *User) CanLogin() bool {
return u.Status == UserStatusActive
}
// 业务规则:激活用户
func (u *User) Activate() error {
if u.Status == UserStatusBanned {
return errors.New("被封禁的用户不能激活")
}
u.Status = UserStatusActive
u.UpdatedAt = time.Now()
return nil
}
2. Domain Service (领域服务)
// domain/user/service/user_service.go
package service
import (
"context"
"errors"
"your-project/domain/user/entity"
"your-project/domain/user/repository"
)
// UserDomainService 用户领域服务
type UserDomainService struct {
userRepo repository.UserRepository
}
func NewUserDomainService(userRepo repository.UserRepository) *UserDomainService {
return &UserDomainService{
userRepo: userRepo,
}
}
// 业务规则:检查用户名是否唯一
func (s *UserDomainService) IsUsernameUnique(ctx context.Context, username string) (bool, error) {
existingUser, err := s.userRepo.FindByUsername(ctx, username)
if err != nil {
return false, err
}
return existingUser == nil, nil
}
// 业务规则:用户注册
func (s *UserDomainService) RegisterUser(ctx context.Context, username, email, phone string) (*entity.User, error) {
// 1. 检查用户名唯一性
unique, err := s.IsUsernameUnique(ctx, username)
if err != nil {
return nil, err
}
if !unique {
return nil, errors.New("用户名已存在")
}
// 2. 创建用户实体
user := &entity.User{
Username: username,
Email: email,
Phone: phone,
Status: entity.UserStatusActive,
}
// 3. 验证业务规则
if err := user.ValidateUsername(); err != nil {
return nil, err
}
// 4. 保存用户
return s.userRepo.Save(ctx, user)
}
3. Repository 接口 (仓储模式)
// domain/user/repository/user_repository.go
package repository
import (
"context"
"your-project/domain/user/entity"
)
// UserRepository 用户仓储接口
type UserRepository interface {
Save(ctx context.Context, user *entity.User) (*entity.User, error)
FindByID(ctx context.Context, id int64) (*entity.User, error)
FindByUsername(ctx context.Context, username string) (*entity.User, error)
FindByEmail(ctx context.Context, email string) (*entity.User, error)
Update(ctx context.Context, user *entity.User) error
Delete(ctx context.Context, id int64) error
List(ctx context.Context, offset, limit int) ([]*entity.User, error)
}
4. 应用层 (Application Layer)
// application/user/service/user_app_service.go
package service
import (
"context"
userDomain "your-project/domain/user/service"
"your-project/application/user/dto"
)
// UserAppService 用户应用服务
type UserAppService struct {
userDomainService *userDomain.UserDomainService
}
func NewUserAppService(userDomainService *userDomain.UserDomainService) *UserAppService {
return &UserAppService{
userDomainService: userDomainService,
}
}
// 用户注册用例
func (s *UserAppService) RegisterUser(ctx context.Context, req *dto.RegisterUserRequest) (*dto.UserResponse, error) {
// 1. 调用领域服务
user, err := s.userDomainService.RegisterUser(ctx, req.Username, req.Email, req.Phone)
if err != nil {
return nil, err
}
// 2. 转换为 DTO
return &dto.UserResponse{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Phone: user.Phone,
Status: string(user.Status),
}, nil
}
🔄 域与域之间的交互
事件驱动交互
// 用户注册成功后,通知其他域
type UserRegisteredEvent struct {
UserID int64 `json:"user_id"`
Username string `json:"username"`
Email string `json:"email"`
}
// 金融域监听用户注册事件,自动创建钱包
func (h *WalletEventHandler) HandleUserRegistered(event UserRegisteredEvent) error {
// 为新用户创建钱包
wallet := &entity.Wallet{
UserID: event.UserID,
Balance: 0.0,
Currency: "CNY",
}
return h.walletRepo.Save(context.Background(), wallet)
}
📊 Domain 的好处
1. 团队协作
用户域团队:专注用户相关功能
├── 张三:负责用户注册登录
├── 李四:负责用户资料管理
└── 王五:负责企业认证
支付域团队:专注支付相关功能
├── 赵六:负责钱包功能
├── 孙七:负责支付流程
└── 周八:负责账单生成
2. 独立部署
# 可以独立部署不同的域
kubectl apply -f user-domain-deployment.yaml
kubectl apply -f payment-domain-deployment.yaml
kubectl apply -f product-domain-deployment.yaml
3. 技术选择自由
用户域:使用 PostgreSQL (复杂查询)
支付域:使用 MySQL (事务性强)
数据域:使用 ClickHouse (分析查询)
4. 测试隔离
// 只测试用户域,不需要启动其他域
func TestUserDomain(t *testing.T) {
// 只需要用户域的依赖
userRepo := mock.NewUserRepository()
userService := service.NewUserDomainService(userRepo)
// 测试用户注册逻辑
user, err := userService.RegisterUser(ctx, "testuser", "test@example.com", "13800138000")
assert.NoError(t, err)
assert.Equal(t, "testuser", user.Username)
}
🎯 总结
Domain(域)就是按业务功能划分的代码组织方式:
- 用户域 - 管理用户相关的所有功能
- 支付域 - 管理支付相关的所有功能
- 产品域 - 管理产品相关的所有功能
- 数据域 - 管理数据查询相关的功能
核心思想:
- 按业务划分,不按技术划分
- 每个域独立开发、测试、部署
- 域之间通过事件或 API 通信
- 团队可以专注于特定业务领域
这样组织代码后,你的项目会更容易理解、维护和扩展!