域驱动设计中 IoC 自动接线的选项
在我最新的 ASP.NET MVC 2 应用程序中,我一直在尝试将域驱动的概念付诸实践设计 (DDD)、单一职责原则 (SRP)、控制反转 (IoC),以及 < a href="http://en.wikipedia.org/wiki/Test_driven_development" rel="nofollow noreferrer">测试驱动开发 (TDD)。作为一个架构示例,我一直在关注 Jeffery Palermo 的“洋葱架构 ”,该内容在 ASP.NET MVC 2 实际操作 中得到了极大的扩展。
虽然我已经开始成功应用这些原则中的大部分(一些?),但我缺少一个关键部分谜题。我无法确定将服务层自动连接到我的域实体的最佳机制。
举个例子:每个需要发送电子邮件的域实体都应该依赖于 IEmailService
接口。根据我的阅读,揭示这种依赖性的最佳实践是使用构造函数注入。在我的 UI 层中,我使用 ASP.NET 中的 StructureMapControllerFactory
对存储库接口实现执行类似的注入MVC 贡献。
我感到困惑的是,将必要的服务自动连接到域实体中的最佳机制是什么?域实体是否应该以这种方式注入?如果我不将 IEmailService 注入域实体中,我将如何使用它?
其他 Stack Overflow 问题是很棒的 DDD、SRP、IoC、TDD 参考:
In my latest ASP.NET MVC 2 application I have been trying to put into practice the concepts of Domain Driven Design (DDD), the Single Responsibility Principle (SRP), Inversion of Control (IoC), and Test Driven Development (TDD). As an architecture example I have been following Jeffery Palermo's "Onion Architecture" which is expanded on greatly in ASP.NET MVC 2 in Action.
While, I have begun to successfully apply most (some?) of these principles I am missing a key piece of the puzzle. I am having trouble determining the best mechanism for auto-wiring a service layer to my domain entities.
As an example: each domain entity that needs the ability to send an email should depend on an IEmailService
interface. From my reading, best practice to reveal this dependency would be to use constructor injection. In my UI layer I perform a similar injection for repository interface implementations using the StructureMapControllerFactory
from ASP.NET MVC Contrib.
Where I am confused is what is the best mechanism for auto-wiring the injection of the necessary services into domain entities? Should the domain entities even be injected this way? How would I go about using IEmailService
if I don't inject it into the domain entities?
Additional Stack Overflow questions which are great DDD, SRP, IoC, TDD references:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
除非我误解了您的意图,而是选择专注于语义,否则我将剖析此声明“作为示例:每个需要发送电子邮件的能力的域实体都应该依赖于 IEmailService 接口。”
我不得不说这本身就是 DDD 的极端混蛋。为什么域实体需要依赖电子邮件服务?国际海事组织不应该。这是没有道理的。
然而,与域实体结合的业务操作需要发送电子邮件。您应该将
IEmailService
依赖项包含在此类中,而不是域实体中。这个类很可能属于几个几乎同义的名称之一:模型、服务或控制器,具体取决于您所在的架构/层。此时,您的
StructureMapControllerFactory
将正确地自动连接所有需要的内容。将使用IEmailService
。虽然我可能有点过度概括,但让域实体成为 POCO 或接近 POCO(以避免违反 SRP)几乎是标准做法,但是为了序列化和验证,域实体中经常会违反 SRP。选择违反 SRP 来解决这些类型的交叉问题更多的是个人信仰立场,而不是“正确”或“错误”的决定。
作为最后的跟进,如果您的问题是真正在独立服务中运行的代码部分(无论是基于 Web 还是基于操作系统)以及如何连接依赖项,则正常的解决方案是在基础上接管服务level 并以与 MVC 中的
StructureMapControllerFactory
相同的类似方式对其应用 IOC。如何实现这一点完全取决于您正在使用的基础设施。响应:
假设您有
IOrderConfirmService
,它有一个方法EmailOrderConfirmation(Order order)
。您最终会得到这样的结果:您将拥有
OrderController
类,该类类似于StrucutreMap,当您正确使用构造函数注入时,它将固有地构建您的整个架构链。这是紧耦合和控制反转之间的根本区别。因此,当 StructureMapFactory 构建控制器时,它首先看到的是它需要 IOrderConfirmService。此时它将检查是否可以直接插入 IOrderConfirmService,但它不能,因为它需要 IEmailService。因此它会检查是否可以插入 IEmailService,出于争论起见,我们可以说它可以。因此,此时它将构建 EmailService,然后构建 MyOrderConfirmService 并插入 EmailService,最后构建 OrderController 并插入 MyOrderConfirmService。这就是术语“控制反转”的由来。 StructureMap 将在整个依赖链中首先构建 EmailService,最后构建 Controller。在紧密耦合的设置中,这将与首先构建控制器并且必须构建业务服务然后构建电子邮件服务相反。与 IOC 相比,紧耦合设计非常脆弱。
Unless I'm misunderstanding your intent and instead I'm choosing to focus on semantics I'm going to dissect this statement "As an example: each domain entity that needs the ability to send an email should depend on an IEmailService interface."
I would have to argue this is upon itself is an extreme bastardization of DDD. Why should a domain entity ever need to depend on an email service? IMO it shouldn't. There is no justification for it.
However there are business operations in conjunction with a domain entity that would require the need to send emails. You should have your
IEmailService
dependency contained in this class here, not the domain entity. This class would most likely fall into one of a few nearly synonymous names: Model, Service or Controller dependent upon which architecture/layer you're in.At this point your
StructureMapControllerFactory
would then correctly auto wire everything that would use theIEmailService
.While I might be minorly over generalizing it's pretty much standard practice to have domain entities be POCOs or be nearly POCOs (to avoid violation of the SRP) however frequently SRP is violated in domain entities for sake of serialization and validation. Choosing to violate SRP for those types of cross cutting concerns is more of a personal belief stance as opposed to a "right" or "wrong" decision.
As a final follow up if your question is on the portion of code that is truly operating in a stand alone service whether web or OS based and how to wire up the dependencies from that, a normal solution would be take over the service at a base level and apply IOC to it in the same similar fashion as the
StructureMapControllerFactory
does in MVC. How to achieve this would be entirely dependent upon the infrastructure you're working with.Response:
Lets say you have
IOrderConfirmService
which has a methodEmailOrderConfirmation(Order order)
. You would end up with something like this:You would then have your
OrderController
class that would be something likeStrucutreMap will inherently build up you're entire architecture chain when you use constructor injection correctly. This is the fundamental difference between tight coupling and inversion of control. So when the StructureMapFactory goes to build up your controller the first thing it will see is that it needs IOrderConfirmService. At this point it will check if it can plug IOrderConfirmService directly which it can't because it needs IEmailService. So it will check if it can plug IEmailService and for argumentsake lets say it can. So at this point it will build EmailService, which it will then build MyOrderConfirmService and plug in EmailService, and then finally build OrderController and plug in MyOrderConfirmService. This is where the term inversion of control comes from. StructureMap will build the EmailService first in the entire chain of dependencies and ending last with the Controller. In a tightly coupled setup this will be the opposite where the Controller will be built first and have to build the business service and then build the email service. Tightly coupled design is very brittle when compared to IOC.