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.Modelsql.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 层,用数据库或其他方式实现这些接口。

相关推荐
稻草人22226 小时前
打造个人Dify?手写AI工作流让AI乖乖听话 - 业务节点实现篇
架构
neoooo6 小时前
Apollo兜底口诀
java·后端·架构
chenchihwen7 小时前
RAG 多模态 API 处理系统设计解析:企业级大模型集成架构实战
架构
文火冰糖的硅基工坊8 小时前
[嵌入式系统-114]:华为的操作系统:鸿蒙操作系统(HarmonyOS)和欧拉操作系统(openEuler)
科技·华为·架构·harmonyos
ZeehLin9 小时前
auipc指令在NEMU中的执行过程
架构
EF@蛐蛐堂9 小时前
WUJIE VS QIANKUN 微前端框架选型(一)
前端·vue.js·微服务·架构
RunningShare10 小时前
高可用架构实战:SpringBoot+MongoDB构建AI原生应用
spring boot·mongodb·架构
Xxtaoaooo10 小时前
Sora文生视频技术拆解:Diffusion Transformer架构与时空建模原理
人工智能·架构·音视频·transformer·sora
银帅1833503097112 小时前
2015年下半年试题三:论面向服务的架构及其应用
架构