我应该在哪个层次上应用依赖注入?控制器还是领域层?

6
我希望听听您对在控制器级别和/或领域级别应用依赖注入的主要优点和缺点的看法。
让我解释一下。如果我收到一个IUserRepository作为我的User的参数,我可以采取两种方式:
1.我直接将IUserRepository注入到我的域对象中,然后在控制器级别使用User而不需要新建对象,这意味着我可以从DI容器中获取它们准备好的对象。
2.我在我的控制器(例如,Register.aspx.cs)上注入IUserRepository,并在那里使用来自DI容器的依赖项创建所有域对象。
昨天,当我和朋友交谈时,他告诉我,如果你从容器中获取域对象,则会失去其生命周期控制,因为容器会为您管理它,他认为这可能会在处理大型xml配置文件时出现错误。这个观点与我不同,因为您可以编写测试循环遍历程序集中的每个域对象,然后询问容器是否是单例、请求范围、会话范围还是应用程序范围。如果其中任何一个为真,则失败。这是确保此类问题不会发生的一种方法。
我更倾向于使用域方法(1),因为我在控制器级别看到了大量重复代码的节省(当然,在XML文件中会有更多的行)。
我朋友提出的另一点是,想象一下,由于某种原因,你被迫从DI容器A更改为B,并且假设B不支持构造函数注入(这是一个“无缝容器”Java的情况,它通过设置器注入来操作BC或仅执行其任务),那么他的观点是,如果我将所有代码放在控制器级别,我可以顺畅地重构我的代码,因为我可以访问像Auto-Refactoring和Auto-Complete这样的工具,而在处理XML文件时则不可用。
我现在陷入了困境,因为我应该立即做出决定。
哪种方法应该利用我的架构?还有其他的思考方式吗?
您认为这是否是一个相关的问题,我应该担心吗?

2
用户为什么需要了解IUserRepository? - Felice Pollano
可能是重复问题:https://dev59.com/4m445IYBdhLWcg3we6V9 - Mark Seemann
我的想法是,它确实是一个(间接的)ActiveRecord,因为我有代表数据库中表的类...这是一个非贫血模型,因为这些实体不仅仅能够存储数据。想象一下,将新用户保存到数据库需要向管理员发送电子邮件,那么在 .Save() 内部,在调用我的存储库上的 .Save() 之后,我会调用 Email.Send("message")。这使得实体变得丰富而不是贫血! - Renato Gama
相关:https://dev59.com/P3M_5IYBdhLWcg3wNwQv - Mark Seemann
1
Renato。一些丰富你的模型的提示,而不将存储库放入实体中,可以是:尝试减少getter和setter属性,并通过值对象封装更多行为。关于发送电子邮件,我会使用域事件来处理。当您将新用户添加到实体Customer.Users (?)集合时触发事件。然后使用存储库保存用户。 - Magnus Backeus
显示剩余3条评论
2个回答

5
如果你想要避免贫血的领域模型,就必须放弃传统的n层、n架构的CRUDY应用程序架构。Greg Young在这篇DDDD论文中解释了为什么要这样做。DI并不能改变这一点。 CQRS将是一个更好的选择,而DI非常适合于这种类型的架构所产生的小型自治组件。

1

我不是Java领域的专家,但根据你在问题中提供的细节,似乎你使用了某种MVC框架(因为你涉及到控制器和领域)。但是,我对如何在领域驱动架构中使用DI有自己的看法。

首先,有几种DDD的实现方式:有些人在演示中使用MVC,没有应用程序服务层在MVC和领域之间。其他人使用MVP(或MVVM),也没有服务层。但是,我认为一些人会同意我的观点,即你很少注入存储库(或其他服务...)。我建议在命令中注入存储库(使用MVC和没有服务层),在Presenter中注入(如果你使用MVP)或在应用程序服务中注入(如果你使用服务层)。我主要使用一个应用程序层,在其中每个服务都在构造函数中获取它们需要注入的存储库。

其次,我不会担心在IoC容器之间切换。现在,大多数容器框架都支持ctor注入,并且可以自动解析参数。现在我知道你是Java开发人员,而我是MS开发人员,但是MS Practices团队有一个通用服务定位器,可以帮助你生成与你使用的容器框架无关的代码。在Java社区中可能也有类似的工具。

所以,选择第二个选项吧。希望我能为你指明正确的方向。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接