Files
tyapi-server/docs/用户域实体优化总结.md
2025-07-11 21:05:58 +08:00

222 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 用户域实体优化总结
## 🎯 **优化目标**
将 User 实体从"贫血模型"升级为"充血模型",将业务逻辑从 Service 层迁移到实体层,实现更好的封装和职责分离。
## ✅ **完成的优化**
### **1. 实体业务方法增强**
#### **密码管理方法**
```go
// 修改密码(包含完整的业务验证)
func (u *User) ChangePassword(oldPassword, newPassword, confirmPassword string) error
// 验证密码
func (u *User) CheckPassword(password string) bool
// 设置密码(用于注册或重置)
func (u *User) SetPassword(password string) error
```
#### **手机号管理方法**
```go
// 验证手机号格式
func (u *User) IsValidPhone() bool
// 设置手机号(包含格式验证)
func (u *User) SetPhone(phone string) error
// 获取脱敏手机号
func (u *User) GetMaskedPhone() string
```
#### **用户状态检查方法**
```go
// 检查用户是否可以登录
func (u *User) CanLogin() bool
// 检查用户是否活跃
func (u *User) IsActive() bool
// 检查用户是否已删除
func (u *User) IsDeleted() bool
```
### **2. 业务规则验证**
#### **密码强度验证**
- 长度要求8-128 位
- 必须包含数字
- 必须包含字母
- 必须包含特殊字符
#### **手机号格式验证**
- 11 位数字
- 以 1 开头
- 第二位为 3-9
#### **业务不变性验证**
- 新密码不能与旧密码相同
- 确认密码必须匹配
- 用户状态检查
### **3. 工厂方法**
```go
// 创建新用户的工厂方法
func NewUser(phone, password string) (*User, error)
```
### **4. 静态工具方法**
```go
// 验证手机号格式(静态方法)
func IsValidPhoneFormat(phone string) bool
// 检查是否为验证错误
func IsValidationError(err error) bool
```
## 🔄 **Service 层重构**
### **优化前的问题**
```go
// 业务逻辑集中在Service中
func (s *UserService) ChangePassword(ctx context.Context, userID string, req *dto.ChangePasswordRequest) error {
// 验证新密码确认
if req.NewPassword != req.ConfirmNewPassword { ... }
// 验证当前密码
if !s.checkPassword(req.OldPassword, user.Password) { ... }
// 哈希新密码
hashedPassword, err := s.hashPassword(req.NewPassword)
// 更新密码
user.Password = hashedPassword
return s.repo.Update(ctx, user)
}
```
### **优化后的改进**
```go
// Service只负责协调业务逻辑委托给实体
func (s *UserService) ChangePassword(ctx context.Context, userID string, req *dto.ChangePasswordRequest) error {
// 1. 获取用户信息
user, err := s.repo.GetByID(ctx, userID)
if err != nil {
return fmt.Errorf("用户不存在: %w", err)
}
// 2. 执行业务逻辑(委托给实体)
if err := user.ChangePassword(req.OldPassword, req.NewPassword, req.ConfirmNewPassword); err != nil {
return err
}
// 3. 保存用户
return s.repo.Update(ctx, user)
}
```
## 📊 **优化效果对比**
| 方面 | 优化前 | 优化后 |
| ---------------- | -------------- | -------------- |
| **业务逻辑位置** | Service 层 | 实体层 |
| **代码复用性** | 低 | 高 |
| **测试难度** | 需要 Mock 仓储 | 可直接测试实体 |
| **职责分离** | 不清晰 | 清晰 |
| **维护性** | 一般 | 优秀 |
## 🧪 **测试覆盖**
### **单元测试**
- ✅ 密码修改功能测试
- ✅ 密码验证功能测试
- ✅ 手机号设置功能测试
- ✅ 手机号脱敏功能测试
- ✅ 手机号格式验证测试
- ✅ 用户创建工厂方法测试
### **测试结果**
```
=== RUN TestUser_ChangePassword
--- PASS: TestUser_ChangePassword (0.57s)
=== RUN TestUser_CheckPassword
--- PASS: TestUser_CheckPassword (0.16s)
=== RUN TestUser_SetPhone
--- PASS: TestUser_SetPhone (0.00s)
=== RUN TestUser_GetMaskedPhone
--- PASS: TestUser_GetMaskedPhone (0.00s)
=== RUN TestIsValidPhoneFormat
--- PASS: TestIsValidPhoneFormat (0.00s)
=== RUN TestNewUser
--- PASS: TestNewUser (0.08s)
PASS
```
## 🚀 **新增功能**
### **1. 用户信息更新**
```go
func (s *UserService) UpdateUserProfile(ctx context.Context, userID string, req *dto.UpdateProfileRequest) (*entities.User, error)
```
### **2. 用户停用**
```go
func (s *UserService) DeactivateUser(ctx context.Context, userID string) error
```
### **3. 软删除支持**
```go
func (r *UserRepository) SoftDelete(ctx context.Context, id string) error
func (r *UserRepository) Restore(ctx context.Context, id string) error
```
## 📈 **架构改进**
### **1. 更好的封装**
- 业务规则与数据在一起
- 减少外部依赖
- 提高内聚性
### **2. 更清晰的职责**
- 实体:业务逻辑和验证
- Service协调和事务管理
- Repository数据访问
### **3. 更容易测试**
- 实体方法可以独立测试
- 不需要复杂的 Mock 设置
- 测试覆盖更全面
## 🎉 **总结**
这次优化成功实现了:
1. **✅ 充血模型** - 实体包含丰富的业务方法
2. **✅ 职责分离** - Service 专注于协调,实体专注于业务逻辑
3. **✅ 更好的封装** - 业务规则与数据紧密耦合
4. **✅ 更容易测试** - 实体方法可以独立测试
5. **✅ 代码复用** - 业务逻辑可以在不同场景下复用
这是一个成功的"轻量级 DDD"实践,在保持架构简单的同时,显著提升了代码质量和可维护性!