当前位置: 首页 > news >正文

多级泛型接口嵌套

多级泛型接口嵌套的设计模式,从基础到业务逐层扩展:

---

层级设计
IBaseDao[T] // 最基础:单实体 CRUD

IGeneralDao[T, R] // 通用层:实体 + 返回类型分离

IBusinessDao[T, Q, R] // 业务层:实体 + 查询条件 + 返回

UserDao // 具体实现


---

第一层:IBaseDao[T]
// 基础 CRUD,T = 实体类型
type IBaseDao[T any] interface {
Insert(entity T) error
UpdateById(id int64, entity T) error
DeleteById(id int64) error
FindById(id int64) (T, error)
FindAll() ([]T, error)
}


---

第二层:IGeneralDao[T, R]
// 通用查询,T = 实体,R = 返回类型(DTO/VO)
type IGeneralDao[T any, R any] interface {
IBaseDao[T] // 嵌入基础接口

// 分页查询
QueryPage(req *pagemodel.PageRequest[T]) *pagemodel.PageResult[R]
QueryOne(req T) (*R, error)

// 转换器(可选)
SetConverter(conv pagemodel.Converter[T, R])
}


---

第三层:IBusinessDao[T, Q, R]
// 业务层,T = 实体,Q = 查询条件,R = 返回
type IBusinessDao[T any, Q any, R any] interface {
IGeneralDao[T, R] // 嵌入通用接口

// 复杂业务查询
QueryByCondition(req Q) *pagemodel.PageResult[R]
QueryByConditionOne(req Q) (*R, error)

// 统计
CountByCondition(req Q) (int64, error)

// 批量操作
BatchInsert(entities []T) error
BatchUpdate(entities []T) error
}


---

具体实现
// 实体
type User struct {
ID int64
Name string
Age int
}

// 查询条件
type UserQuery struct {
NameLike string
AgeMin int
AgeMax int
}

// 返回 DTO
type UserDTO struct {
ID string `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}

// ========== 基础 DAO 实现 ==========
type BaseDao[T any] struct {
DB *gorm.DB
}

func (d *BaseDao[T]) Insert(entity T) error {
return d.DB.Create(&entity).Error
}

func (d *BaseDao[T]) FindById(id int64) (T, error) {
var t T
err := d.DB.First(&t, id).Error
return t, err
}

// ... 其他基础方法

// ========== 通用 DAO 实现 ==========
type GeneralDao[T any, R any] struct {
BaseDao[T]
conv pagemodel.Converter[T, R]
}

func (d *GeneralDao[T, R]) QueryPage(req *pagemodel.PageRequest[T]) *pagemodel.PageResult[R] {
var list []T
var total int64

db := d.DB.Model(new(T))
// ... 构建查询

db.Count(&total)
db.Offset((req.PageCurrent - 1) * req.PageSize).Limit(req.PageSize).Find(&list)

// 转换
result := &pagemodel.PageResult[T]{
PageResult: &page.PageResult{
Total: total,
PageCurrent: req.PageCurrent,
PageSize: req.PageSize,
},
Data: list,
}

return pagemodel.PageTo(result, d.conv)
}

func (d *GeneralDao[T, R]) SetConverter(conv pagemodel.Converter[T, R]) {
d.conv = conv
}

// ========== 业务 DAO 实现 ==========
type UserDao struct {
GeneralDao[User, UserDTO] // 嵌入通用实现
}

// 实现业务层特有方法
func (d *UserDao) QueryByCondition(req UserQuery) *pagemodel.PageResult[UserDTO] {
db := d.DB.Model(&User{})

if req.NameLike != "" {
db = db.Where("name LIKE ?", "%"+req.NameLike+"%")
}
if req.AgeMin > 0 {
db = db.Where("age >= ?", req.AgeMin)
}
if req.AgeMax > 0 {
db = db.Where("age <= ?", req.AgeMax)
}

var list []User
var total int64
db.Count(&total).Find(&list)

result := &pagemodel.PageResult[User]{
PageResult: &page.PageResult{Total: total},
Data: list,
}

return pagemodel.PageTo(result, d.conv)
}

func (d *UserDao) CountByCondition(req UserQuery) (int64, error) {
var count int64
db := d.DB.Model(&User{})
// ... 条件构建
err := db.Count(&count).Error
return count, err
}


---

使用方式
// 创建 DAO
userDao := &UserDao{
GeneralDao: GeneralDao[User, UserDTO]{
BaseDao: BaseDao[User]{DB: db},
conv: pagemodel.Converter[User, UserDTO]{},
},
}

// 基础 CRUD(来自 IBaseDao)
user, err := userDao.FindById(1)

// 通用查询(来自 IGeneralDao)
result := userDao.QueryPage(&pagemodel.PageRequest[User]{
PageCurrent: 1,
PageSize: 10,
})

// 业务查询(来自 IBusinessDao)
dtoResult := userDao.QueryByCondition(UserQuery{
NameLike: "张",
AgeMin: 18,
AgeMax: 30,
})


---

接口断言与多态
// 按层级使用接口
var base IBaseDao[User] = userDao
var general IGeneralDao[User, UserDTO] = userDao
var business IBusinessDao[User, UserQuery, UserDTO] = userDao

// 函数接受不同层级接口
func UseBase[T any](dao IBaseDao[T]) { ... }
func UseGeneral[T, R any](dao IGeneralDao[T, R]) { ... }
func UseBusiness[T, Q, R any](dao IBusinessDao[T, Q, R]) { ... }

// 调用
UseBase(userDao)
UseGeneral(userDao)
UseBusiness(userDao)


---

依赖注入(godi 风格)
// 注册到容器
godi.Register(IBusinessDao[User, UserQuery, UserDTO], func() any {
return &UserDao{
GeneralDao: GeneralDao[User, UserDTO]{
BaseDao: BaseDao[User]{DB: godi.Get(*gorm.DB)},
conv: pagemodel.Converter[User, UserDTO]{},
},
}
})

// 使用
var userDao = godi.Get(IBusinessDao[User, UserQuery, UserDTO])
result := userDao.QueryByCondition(query)


---

设计要点总结
层级 泛型参数 职责 复用方式
IBaseDao[T] 1个 基础 CRUD 嵌入
IGeneralDao[T, R] 2个 分页 + 转换 嵌入 + Converter
IBusinessDao[T, Q, R] 3个 复杂业务查询 业务实现
关键技巧:
- 上层接口嵌入下层接口
- 实现结构体嵌入上层实现
- Converter[T, R] 解耦实体与 DTO
- 泛型参数逐层增加,不破坏已有代码

http://www.jsqmd.com/news/751402/

相关文章:

  • 新手福音:用快马AI助手轻松学习《我的世界》复杂指令,告别死记硬背
  • 终极指南:使用BilibiliDown从B站视频中提取无损音频的完整教程 [特殊字符]
  • 为OpenClaw智能体工作流配置统一的模型调用后端
  • 自动驾驶安全新视角:用DriveAct数据集,聊聊如何让AI看懂司机的‘小动作’
  • 3步轻松解密微信聊天记录:WechatDecrypt工具使用全攻略
  • 紧急!.NET 9 RC2已移除旧AI API——3小时内迁移至Microsoft.AI.Inference新命名空间(含兼容性映射表与单元测试迁移模板)
  • 告别兼容性烦恼!OpenTabletDriver跨平台数位板驱动终极指南
  • STC32F12单片机驱动WS2812B灯带:一个IO口搞定炫彩灯效(附完整代码)
  • League-Toolkit:英雄联盟玩家的智能游戏管家
  • 如何用3分钟掌握WindowResizer:彻底解决Windows窗口尺寸限制难题
  • Shiro框架下Secure Cookie引发的302循环重定向,一个配置项如何让登录接口‘罢工’?
  • FHIR R5 to 2026版迁移实录:C# .NET 6+医疗系统零停机适配的7步工业级实施手册
  • 终极指南:如何将你的旧电视盒子变成强大的Linux服务器
  • 利用快马AI五分钟生成Python串口调试助手原型,加速硬件调试
  • 3个数据洞察让《碧蓝幻想:Relink》输出效率翻倍:GBFR Logs实战指南
  • SoC验证实战:从C代码到波形,手把手教你定位CPU挂死和MEM_COMPARE失败
  • 2026移动排插什么牌子好?安全与实用性兼具的选择 - 品牌排行榜
  • 3步掌握Translumo:终极免费实时屏幕翻译工具使用指南
  • 为 Hermes Agent 工具链配置 Taotoken 作为自定义模型提供方
  • [笔记] P4824 [USACO15FEB] Censoring S
  • 3步实现单机游戏分屏协作:Nucleus Co-Op终极指南
  • 5分钟掌握Unlock Music:终极浏览器音频解密转换完全指南
  • PPTX2HTML:纯JavaScript前端技术实现PPTX到HTML的无服务器转换方案
  • 5个简单技巧:用Windows Cleaner快速解决C盘空间不足问题
  • 5分钟快速上手:打造macOS桌面歌词显示的终极解决方案
  • DDR5内存的On Die ECC到底有啥用?和传统ECC内存条有啥区别?
  • GDSDecomp终极指南:如何高效反编译Godot游戏资源与脚本
  • 021、PCIE IO读写事务:从一次诡异的设备失联说起
  • 2026 国内可用稳定临时邮箱最新指南
  • Allegro模块复用踩坑实录:MDD文件找不到、位号冲突?这些细节决定成败