如果接口是在业务层而不是数据访问层中定义的,则您不了解接口

时间:2015-03-23 06:53:26

标签: c# dependency-injection domain-driven-design n-tier-architecture

请有人帮我澄清一下我依赖倒置原则的问题。如果我在DAL中有一个看起来像这样的存储库,并且在DAL中有相应的接口。我基本上是对那些会使用我的DAL的人说,#34;这里是一个使用名为' FindEvents'的界面,这是我通过界面签订的合同。所以开发人员知道不要直接使用该对象,而是使用我的界面。我甚至可以将对象设为私有,只将接口公开为公共

DAL -

public class YogaSpaceEventRepository : IYogaSpaceEventRepository
{
    public IQueryable<YogaSpaceEvent> FindEvents(DateTime start, DateTime end)
    {
    // Retrieve Data from Database
    }
} 

public interface IYogaSpaceEventRepository : IDisposable
{
    // here my repo (data access layer) is referencing my business layer to return YogaSpaceEvent
    IQueryable<YogaSpaceEvent> FindEvents(DateTime start, DateTime end); 
}

但是如果我取出这个界面并将其粘贴在BLL(DDD方法)中,那么我就可以避免循环引用(DAL需要引用BLL来理解对象&#39; YogaSpaceEvent&#39;它&#39;它&#39; ; s返回我的BLL中的某个地方我需要调用FindEvents - 现在它是循环的)。这完全打破了界面规则!?因为现在如果DAL开发人员移交DAL程序集,那么作为使用该DAL程序集的开发人员,您不知道可以更改的内容(没有合同 - DAL中没有接口)!

通过

public interface IYogaSpaceEventRepository : IDisposable
{
    // here my repo (data access layer) is referencing my business layer to return YogaSpaceEvent
    IQueryable<YogaSpaceEvent> FindEvents(DateTime start, DateTime end); 
}

你是不是打破了界面的一条规则?这是一份合同--DAL的开发人员不能说这是我的图书馆,我只保证这个界面中有什么。现在没有接口,因此没有合同。

请有人在这里给我一些反馈!

4 个答案:

答案 0 :(得分:7)

如果你转到the source of the Dependency Inversion Principle,你会看到:

  

“客户[...]拥有抽象接口”(第11章)

因此,接口不应该进入DAL,而应进入使用该接口的库中。

在那里,遵守其他SOLID原则也很重要,在这种情况下尤其是接口隔离原则,因此不要在接口上放置比客户端要求更多的成员。

在构图方面,您可能会发现以下内容:

答案 1 :(得分:2)

简单的答案是你没有把它放在你的BLL或DAL中 - 你把它放在第三个只包含合同项目的程序集中 - 即接口和它可能使用的任何基本实体。

您显然理解将数据访问逻辑与业务层分离的原因。如果您打算使用接口,将它包含在实现DAL的程序集中几乎是多余的 - 这是因为接口和实现之间很少或根本没有关注点 - 您将更改它们随意和锁定步骤。

拥有界面的目的是说这就是我实现的任何 DAL的样子,并且任何调用者都应该能够在不更改的情况下调用任何这些DAL实现。考虑一下你是否在数据存储库之间做出选择 - 一个在SQL Server中,一个在MySQL中,一个在云中 - 这三个应该实现相同的接口。

如果你可以明确地说你只会有一个DAL,那么考虑省去界面,除非你在第三个装配中保留它。在这种情况下,界面并非毫无价值,你只是没有充分利用它。

  

如果我将其从DAL中删除并进入其他组件,那么我尝试与使用我的DAL的人签订的任何合同都不存在。那么这不会破坏界面的目的吗?

我不确定我是否理解你在该声明中的位置.... 如果其他人调用你的DAL,他们需要创建一个具体的实例(有多种方法可以做到这一点),但是他们应该将它转换为IDalLayer接口。如果您的DAL返回存储库,那么它们也应该是通用接口。这意味着您的IRepository接口可以在与IDalLayer接口相同的独立程序集中定义,或者甚至可以在不同的程序集中定义。没有必要在DAL实现程序集中定义它。

答案 2 :(得分:1)

Onion Architecture为这类问题提供了良好的指导。我们的想法是,层和依赖关系之间存在严格的层次结构,只有一种方式,这使得事情变得更加简单。当具体实现位于洋葱边缘而不是其抽象时,依赖性反转用于(少数)情况。

关键要点是:

  • 域是最内层,因此它不会引用除自身之外的任何内容。此外(DDD规则)没有任何域名业务知道实体应该保留的时间或方式

  • 因此,在您的示例中,YogaSpaceRepository.FindEvents()不是由域调用,而是由应用服务调用。

  • 存储库接口在域层(或其周围的层)中声明,但在基础架构层中实现。

答案 3 :(得分:0)

皮肤猫的方法有很多种。)

我同意@MarkSeemann,界面应该在你需要的地方声明,在这种情况下你的BLL,但这并不意味着实现需要在同一层声明你可以在你的DAL中实现它,你的DI容器将确保在运行时注入正确的实现

当您考虑发送电子邮件以响应域中的操作时,这会更有意义。我想您想要抽象实际从域发送电子邮件的代码,但您的域名仍将命令 时发送电子邮件,这是一个完美的例子,接口可以在域层中声明,但在其他地方实现

  

但是如果我取出这个界面并将其粘贴在BLL(DDD方法)

但是我不认为域对象应该现在关于持久性的任何内容,但是如果你的设计合理,那么