使用 DI 时,存储库接口属于哪一层?



我最近加入了一个大型团队/项目,该团队/项目在整个解决方案中使用存储库模式和依赖项注入。我注意到存储库接口位于数据层项目中,需要业务层项目直接依赖它。我的理解是,在使用 DI 时,您希望反转此依赖关系,以将业务逻辑与数据访问(数据引用接口与业务层)分离。当我向团队提出这个建议时,反应不一。他们没有看到好处并反对它("每个人都知道不要直接引用具体类型","我们永远不需要更换我们的数据访问技术"等)。

将存储库接口与实现(数据层)保留在同一项目中是否是一种好的做法?如果业务层仅引用数据层的存储库接口,则此设置有什么缺点吗?

这一切都取决于。一位智者曾经说过:

摘要[应该]由上层/策略层拥有

您可能已经阅读了Mark Seemann的优秀著作《.NET 中的依赖注入》,他在书中展示了这一原则(请参阅第 1 版的第 2.2 节和第 2 版的第 3 章),并举例说明了您正在描述的确切场景(即作为域层一部分的存储库接口)。

Mark Seemann 为这样做给出的最重要的论点是因为它允许您用不同的技术替换数据访问技术,这可能是您可能认为的更有可能的情况,特别是考虑到我们现在生活的世界,一切都迁移到云中,在云中您可能没有(或不想)使用相同的数据访问技术。

但是还有其他原因想要将核心层(域层)与应用程序的其余部分隔离开来,并让一切都依赖于应用程序最重要的部分。

我想到的一件事是,开发人员不可能意外地将此层耦合到系统的易失性(或不纯)部分,从而使以后更难更改。对数据访问功能的依赖是一件显而易见的事情,因为它会使测试更加困难,但也要考虑意外地将域层耦合到System.Web,使开发人员可以在系统的该部分中使用HttpContext。很有可能,一旦您有了依赖关系(从域层到数据访问层),随着时间的推移,反转将变得更加困难。

另一方面,这种高度隔离是否有利于您的应用显然取决于很多因素。特别是当应用程序已经以这种方式设计时,最好先将注意力集中在其他改进上。

不要忘记,依赖反转原则(DIP)和依赖注入(DI)最重要的部分是类依赖于抽象。这样可以实现松耦合,松耦合提高了可维护性。由于这些开发人员已经在练习 DI,因此他们已经处于一个很好的位置。

我所做的一个典型的改进是摆脱大多数存储库,并引入更高级别的概念,例如业务操作的通用抽象,查询的通用抽象,有时还有域事件。这会将存储库的使用限制在域层内部。在引入此功能时,这是反转使用这些概念的新(或迁移)代码的依赖项的好时机,而不是通常违反大多数 SOLID 原则的I[EntityName]RepositoryI[EntityName]Service抽象。

我提倡的另一件事是防止应用程序的核心层依赖于某些第三方日志记录库的记录器抽象。这再次归结为DIP,它指出应用程序应拥有抽象,当应用程序依赖于第三方抽象时,情况并非如此。这就是为什么我提倡这样的事情。

就我个人而言,我一直有依赖项从最低级别"流动"到最高级别。UI 需要与业务逻辑交互,因此它依赖于服务接口。服务/业务逻辑需要数据访问,因此它依赖于存储库接口来执行此操作。

这是我在大多数代码库中看到的一般方法。

它属于应用程序中的数据访问层。

最新更新