请有人帮我澄清一下我依赖倒置原则的问题。如果我在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的开发人员不能说这是我的图书馆,我只保证这个界面中有什么。现在没有接口,因此没有合同。
请有人在这里给我一些反馈!
答案 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方法)
中
但是我不认为域对象应该现在关于持久性的任何内容,但是如果你的设计合理,那么