领域驱动设计(DDD):Repository能否在Domain Service中使用?
领域驱动设计场景实现方案
认知错误修正
你对「Repository不应该在域层被调用」的认知存在偏差,该结论混淆了Repository的接口定义与具体实现:
- DDD分层规则中,Repository的业务接口契约是定义在域层的,属于领域模型的一部分,代表领域对聚合根存储、查询能力的抽象要求
- 只有Repository的具体技术实现(如基于JPA、MongoDB的数据库操作类)需要放在基础设施层
域层的Domain Service完全可以依赖自身定义的Repository接口,不会违反分层依赖原则。
场景标准实现方案
1. 域层定义WatchTimeRepository接口
不要定义通用CRUD方法,直接声明贴合业务语义的查询方法,属于领域契约的一部分:
// 存放于域层的Repository接口 public interface WatchTimeRepository { // 查询符合播放条件的前N条WatchTime List<WatchTime> findEligibleWatchTimes(int limit, int rankThreshold); }
2. 域层实现Domain Service承载业务逻辑
将rank筛选的核心业务逻辑放在域服务中,依赖上面定义的Repository接口:
// 存放于域层的领域服务 public class WatchTimeAllocationService { private final WatchTimeRepository watchTimeRepository; public WatchTimeAllocationService(WatchTimeRepository watchTimeRepository) { this.watchTimeRepository = watchTimeRepository; } public List<WatchTime> getWatchTimeBatchForUser(int batchSize) { // 核心业务逻辑:计算当前rank筛选阈值 int currentRankThreshold = calculateRankThreshold(); // 调用Repository接口查询数据 List<WatchTime> candidateList = watchTimeRepository.findEligibleWatchTimes(batchSize, currentRankThreshold); // 可补充其他业务校验,如过滤已向当前用户曝光过的任务、排除已完成播放的任务等 return candidateList; } private int calculateRankThreshold() { // 你的rank算法实现,如根据平台总任务量、剩余播放缺口、用户等级等动态调整阈值 // 纯业务逻辑,无外部依赖 } }
3. 基础设施层实现Repository接口
将具体的数据库查询逻辑放在基础设施层,实现域层定义的Repository接口:
// 存放于基础设施层的Repository实现 public class JpaWatchTimeRepository implements WatchTimeRepository { private final JpaRepository<WatchTimePO, Long> jpaRepository; @Override public List<WatchTime> findEligibleWatchTimes(int limit, int rankThreshold) { // 具体查询逻辑:筛选rank≥阈值、已完成播放量<最大购买播放量的记录,取前limit条 // 将数据库PO转换为域层WatchTime实体后返回 } }
4. 上层调用
应用层/接口层直接调用域服务的getWatchTimeBatchForUser方法即可,无需关心内部业务逻辑与数据查询细节。
关于Value Object的补充建议
你开头提到对Value Object的创建存在困惑,当前场景中WatchTime实体的Video URL、MaxViews、CurrentViews、rank属性都可以设计为Value Object,将属性合法性校验(如Video URL必须为合法YouTube链接、播放量必须为正整数、rank取值范围校验)封装在Value Object内部,避免业务逻辑散落在应用各处。
内容的提问来源于stack exchange,提问作者Yamin Nather
相关产品推荐
相关产品推荐

