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

相关推荐
凤凰战士芭比Q7 小时前
LNMP环境部署 KodBox私有云盘
linux·架构
小猪咪piggy8 小时前
【微服务】(4) 负载均衡
微服务·云原生·架构
短视频矩阵源码定制10 小时前
矩阵系统哪个好?2025年全方位选型指南与品牌深度解析
java·人工智能·矩阵·架构·aigc
小猪咪piggy11 小时前
【微服务】(3) 服务注册与发现
微服务·云原生·架构
刺客_Andy12 小时前
React 第五十二节 Router中 useResolvedPath使用详解和注意事项示例
前端·react.js·架构
推理幻觉13 小时前
IDE/编码代理架构与 Cursor 相关研究(汇总)
ide·人工智能·架构·agent
C++chaofan14 小时前
MyBatis - Plus学习笔记
java·spring boot·笔记·后端·mysql·架构·mybatis
猫林老师14 小时前
Flutter for HarmonyOS开发指南(二):混合开发架构与通信机制
flutter·架构·harmonyos
绝无仅有17 小时前
大厂面试相关文章:深入技术面试中的核心知识点
后端·面试·架构
绝无仅有17 小时前
面试文章:网络协议与redis安全,https协议,TCP三次握手,四次挥手等面试经典问题
后端·面试·架构