7

在我最新的 ASP.NET MVC 2 应用程序中,我一直在尝试将领域驱动设计 (DDD)单一责任原则 (SRP)控制反转 (IoC)测试驱动开发 (TDD)的概念付诸实践。作为一个架构示例,我一直在关注 Jeffery Palermo 的“洋葱架构”,它在ASP.NET MVC 2 in Action中得到了极大的扩展。

洋葱架构图

虽然,我已经开始成功地应用这些原则中的大部分(一些?),但我错过了这个难题的关键部分。我无法确定将服务层自动连接到我的域实体的最佳机制。

例如:每个需要能够发送电子邮件的域实体都应该依赖于一个IEmailService接口。根据我的阅读,揭示这种依赖关系的最佳实践是使用构造函数注入。StructureMapControllerFactory在我的 UI 层中,我使用ASP.NET MVC Contrib为存储库接口实现执行类似的注入。

我感到困惑的是,将必要的服务自动注入域实体的最佳机制是什么?域实体是否应该以这种方式注入?IEmailService如果我不将它注入到域实体中,我将如何使用?

其他堆栈溢出问题是很好的 DDD、SRP、IoC、TDD 参考:

4

1 回答 1

5

除非我误解了您的意图,而是选择专注于语义,否则我将剖析这句话“例如:每个需要能够发送电子邮件的域实体都应该依赖于 IEmailService 接口。”

我不得不争辩说,这本身就是对 DDD 的极端混蛋。为什么域实体需要依赖电子邮件服务?海事组织不应该。没有理由这样做。

但是,与需要发送电子邮件的域实体相关的业务操作。您应该将您的IEmailService依赖项包含在此类中,而不是域实体中。此类很可能属于几个几乎同义的名称之一:模型、服务或控制器,具体取决于您所在的架构/层。

此时,您StructureMapControllerFactory将正确地自动连接所有将使用IEmailService.

虽然我可能略微过度概括,但将域实体设为 POCO 或接近 POCO(以避免违反 SRP)几乎是标准做法,但为了序列化和验证,域实体中经常违反 SRP。为这些类型的交叉关注选择违反 SRP 更多的是个人信仰立场,而不是“正确”或“错误”的决定。

作为最后的跟进,如果您的问题是关于真正在独立服务中运行的代码部分,无论是基于 Web 还是基于操作系统,以及如何连接依赖关系,一个正常的解决方案是在基础上接管该服务水平并以与StructureMapControllerFactoryMVC 中类似的方式对其应用 IOC 。如何实现这一点将完全取决于您正在使用的基础架构。

回复:

可以说你有IOrderConfirmServicewhich has a method EmailOrderConfirmation(Order order)。你最终会得到这样的结果:

public class MyOrderConfirmService : IOrderConfirmService
{    
    private readonly IEmailService _mailer;

    public MyOrderConfirmService(IEmailService mailer)
    {        
        _mailer = mailer;        
    }

    public void EmailOrderConfirmation(Order order)
    {        
        var msg = ConvertOrderToMessage(order); //good extension method candidite
        _mailer.Send(msg);        
    }    
}

然后,您的OrderController课程将类似于

public class OrderController : Controller
{    
    private readonly IOrderConfirmService _service;

    public OrderController(IOrderConfirmService service)
    {        
        _service= service;        
    }

    public ActionResult Confirm()
    {      
            _service.EmailOrderConfirmation(some order);

            return View();
    }    
}

当您正确使用构造函数注入时,StrucutreMap 将固有地构建您的整个架构链。这是紧耦合和控制反转之间的根本区别。因此,当 StructureMapFactory 开始构建您的控制器时,它首先会看到它需要 IOrderConfirmService。此时它会检查它是否可以直接插入 IOrderConfirmService,但它不能,因为它需要 IEmailService。所以它会检查它是否可以插入 IEmailService 并且为了争论可以说它可以。所以此时它将构建EmailService,然后构建MyOrderConfirmService并插入EmailService,最后构建OrderController并插入MyOrderConfirmService。这就是术语控制反转的来源。StructureMap 将在整个依赖链中首先构建 EmailService,最后以 Controller 结束。在紧密耦合的设置中,这将与首先构建控制器并且必须构建业务服务然后构建电子邮件服务的情况相反。与 IOC 相比,紧耦合设计非常脆弱。

于 2010-07-15T17:26:05.427 回答