# 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 层的职责 ```go // 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 (领域服务) ```go // 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 接口 (仓储模式) ```go // 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) ```go // 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 } ``` ## 🔄 域与域之间的交互 ### 事件驱动交互 ```go // 用户注册成功后,通知其他域 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. **独立部署** ```bash # 可以独立部署不同的域 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. **测试隔离** ```go // 只测试用户域,不需要启动其他域 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(域)就是按业务功能划分的代码组织方式**: 1. **用户域** - 管理用户相关的所有功能 2. **支付域** - 管理支付相关的所有功能 3. **产品域** - 管理产品相关的所有功能 4. **数据域** - 管理数据查询相关的功能 **核心思想**: - 按业务划分,不按技术划分 - 每个域独立开发、测试、部署 - 域之间通过事件或 API 通信 - 团队可以专注于特定业务领域 这样组织代码后,你的项目会更容易理解、维护和扩展!