You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DDD架构下应用层仓储接口可否复用基础设施层基类实现

结论

结合你给出的项目背景,你的方案合理性远高于同事的方案,理由如下:

对同事两个顾虑的回应

  • 关于「AddAsync命名过于泛化、无法判断添加实体类型」的问题
    你们项目本身遵循SOLID原则,单处理器仅处理单一聚合根,且命名规范清晰,实际调用代码一定是IOrderRepository orderRepository注入后调用orderRepository.AddAsync(order),不管是仓储变量名、还是入参的Order类型,都能100%明确操作的实体类型,不存在歧义。反而orderRepository.AddOrderAsync(order)属于冗余命名,重复的语义信息反而不符合干净代码的命名规范。
  • 关于「不应当在接口中暴露基类方法、基类方法仅应在继承层级暴露」的问题
    这是对基类职责的误解:你们的BaseRepository<T,U>本质是通用仓储实现的抽离层,核心作用就是提供可复用的公共CRUD实现给子类仓储使用,而非封装仅内部可见的私有逻辑。仓储接口定义的是对外的业务契约,只要该方法是契约要求的能力,实现来源是基类还是子类本身并不影响合理性。同事的方案等于人为限制了基类的复用价值,强制每个子类编写重复的转发逻辑,反而增加了复制粘贴引发的bug风险,比如示例中每个仓储都要单独写日志捕获逻辑,漏写、错写的概率会大幅提升。

你的方案的核心优势

  1. 大幅减少样板代码:无需每个仓储重复编写AddXXXAsync转发方法,示例中的异常日志捕获逻辑也可以统一抽离到基类AddAsync中,后续要调整日志规则仅需修改基类一处即可,维护成本大幅降低。
  2. 完全保留扩展性:基类方法声明为public virtual,如果后续某个聚合的添加逻辑需要特殊处理(比如新增前置校验、触发领域事件等),直接在对应子类仓储中重写AddAsync方法即可,符合开闭原则。
  3. 符合行业通用实践:.NET生态中主流的DDD框架(如ABP等)的仓储实现都采用该模式,通过通用仓储接口定义标准CRUD方法,业务聚合仓储继承通用接口,兼顾复用性和灵活性。

折中方案(如果同事仍有顾虑)

可以额外定义泛型通用仓储接口:

public interface IRepository<T> where T : class
{
    IUnitOfWork UnitOfWork { get; }
    Task AddAsync(T entity);
    // 其他通用CRUD方法
}

业务聚合的仓储接口直接继承该通用接口即可:

public interface IOrderRepository : IRepository<Order>
{
    // 仅需声明订单独有的仓储方法即可
}

既不需要每个接口重复声明通用方法,也符合接口隔离原则,不需要通用CRUD能力的聚合可以不继承该通用接口。


内容的提问来源于stack exchange,提问作者RealYlem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 18:36:00