DDD::repo.go

repo.go 里面写的都是接口

ChatGPT said:

💯 完全正确!你抓到了 DDD 和 Kratos 架构的一个核心原则。

是的------repo.go(或 repository.go) 文件里写的就是接口(interface) ,不写具体实现。

下面我来系统讲清楚:为什么要这么做、repo 接口应该长什么样、它和 data 层是怎样配合的。


🧩 一、repo.go 是干嘛的?

在 DDD(领域驱动设计)中,仓储(Repository)是领域层的一部分,用来:

把领域对象(Entity / Aggregate)从持久化介质中取出或保存进去,

并屏蔽数据库等基础设施的细节。

也就是说:

  • 领域层(domain) 只定义仓储接口(描述"要干什么");
  • 数据层(data) 来实现这些接口(描述"怎么干")。

📦 二、典型的 repo.go 示例

假设我们在 internal/domain/order/ 下有一个 repo.go:

scss 复制代码
package order

import "context"

// Repository 是订单仓储接口
type Repository interface {
	// 保存订单
	Save(ctx context.Context, order *Order) error

	// 根据ID获取订单
	FindByID(ctx context.Context, id OrderID) (*Order, error)

	// 获取用户的所有订单
	ListByUserID(ctx context.Context, userID string) ([]*Order, error)

	// 删除订单
	Delete(ctx context.Context, id OrderID) error
}

特点:

  • ✅ 只定义接口(不关心怎么实现);
  • ✅ 入参/出参都是领域对象(Order, OrderID);
  • ✅ 不暴露数据库类型(如 gorm.Model、sql.DB);
  • ✅ 语义贴近领域(Save、FindByID、ListByUserID)。

🏗️ 三、为什么接口放在领域层?

👉 这是 依赖倒置原则(Dependency Inversion Principle) 的体现:

层 职责 依赖方向
usecase 调用仓储做业务逻辑 依赖 domain.Repository 接口
domain 定义领域模型 + 仓储接口 不依赖下层
data 实现仓储接口 依赖 domain.Repository 定义

也就是说:

kotlin 复制代码
usecase ───→ domain (interface)
             ↑
             └── data (implementation)

这样:

  • usecase 只知道接口,不知道数据库;
  • data 层只管实现接口,替换实现不会影响上层逻辑;
  • 业务层和数据层完全解耦。

⚙️ 四、对应的 data 层实现

在 internal/data/order_repo.go:

go 复制代码
package data

import (
	"context"
	"ddd-kratos/internal/domain/order"
)

type orderRepo struct {
	data *Data // Data 持有数据库、缓存等实例
}

// NewOrderRepo 是仓储的构造函数
func NewOrderRepo(data *Data) order.Repository {
	return &orderRepo{data: data}
}

func (r *orderRepo) Save(ctx context.Context, o *order.Order) error {
	return r.data.db.WithContext(ctx).Save(o).Error
}

func (r *orderRepo) FindByID(ctx context.Context, id order.OrderID) (*order.Order, error) {
	var entity order.Order
	if err := r.data.db.WithContext(ctx).First(&entity, "id = ?", id).Error; err != nil {
		return nil, err
	}
	return &entity, nil
}

func (r *orderRepo) ListByUserID(ctx context.Context, userID string) ([]*order.Order, error) {
	var list []*order.Order
	err := r.data.db.WithContext(ctx).Where("user_id = ?", userID).Find(&list).Error
	return list, err
}

func (r *orderRepo) Delete(ctx context.Context, id order.OrderID) error {
	return r.data.db.WithContext(ctx).Delete(&order.Order{}, "id = ?", id).Error
}

🧠 五、这样分层的好处

优点 说明
✅ 解耦 业务逻辑不依赖数据库实现
🧪 可测试 usecase 层可以用 mock repository 测试
🔄 可替换 想从 MySQL 换成 MongoDB,只需改 data 层
🧱 结构清晰 domain 纯业务,data 纯实现

✅ 总结一句话

repo.go 写的是 仓储接口 ,位于 domain 层;

它定义了"要提供什么数据访问能力",而不管"怎么实现";

具体的实现放在 data 层,用数据库或其他方式实现这些接口。

相关推荐
阿狸猿1 小时前
事件驱动架构(EDA)的设计与应用
架构
硅基手札2 小时前
CAN 技术系列 08 · CAN 控制器寄存器与 IP 架构
驱动开发·架构·嵌入式开发·通信协议·can总线
微三云 - 廖会灵 (私域系统开发)2 小时前
企业级 SaaS 系统架构设计:单体、微服务还是模块化单体?技术选型实战
微服务·架构·系统架构
智慧物业老杨3 小时前
包干制小区物业系统:面向成本管控的架构与落地实践
架构
北漂人Java4 小时前
单智能体三:Router-Skill 工业级 Agent 分工解耦架构,解决大模型技能泛滥难题
架构
懿路向前5 小时前
唤醒工作台全实录(六):数据层——5ms 竞态窗口与“查询即引用“
华为·架构·harmonyos
pt10435 小时前
Cisco设备网络安全系列-20:DevSecOps集成
网络·安全·架构
ai_xiaogui5 小时前
PanelAI项目实战:从AI一键生成到企业级AI基础设施操作系统PPT手搓复盘与架构落地
人工智能·架构·一键部署·panelai·企业级ai基础设施操作系统·ai智能底层操作系统·算力变现
Dawson Zhu6 小时前
【Runtime推理引擎①】Runtime架构设计:从Session到Graph Executor的完整骨架
人工智能·语言模型·架构·aigc·agi
郝学胜-神的一滴6 小时前
AI 编程智能体 20:技术栈选型与架构落地全攻略
人工智能·python·架构·langchain·1024程序员节·智能体