【问题标题】:Onion Architecture should we inject domain models into the presentation layer?我们应该将领域模型注入表示层吗?
【发布时间】:2014-01-30 09:39:18
【问题描述】:

我正在尝试为 ASP.Net MVC 5 项目实现 Onion 架构。我已经看到一些观点认为服务应该被注入而不是实例化,如果我错了,请纠正我,Jeffery Palermo (http://jeffreypalermo.com/blog/the-onion-architecture-part-3/) 表达的想法是任何外层都应该能够直接调用任何内层。所以我的问题是

  1. 洋葱架构可以在没有 IOC 的情况下工作吗?如果可以,是否理想?
  2. 假设我们使用 IOC,如果 UI 不应该知道 领域服务,我们是否应该将相同的原则应用于领域模型 他们自己例如将模型注入 UI 而不是引用 直接?

我理解为什么有些解决方案将 IOC 应用于域服务,但直接在控制器中访问域模型。

【问题讨论】:

  • 如何将模型注入 UI?你能发布一些代码示例吗?
  • 洋葱架构(又名端口和适配器)的整个想法是进行依赖倒置/IoC,所以你不能没有它。
  • @Hippoom 这需要我们为每个领域模型创建接口,然后使用 Autofac 之类的 IOC 注入具体实现
  • @JoeiHuang 不,它没有。领域模型是具体的。服务、持久性应该被抽象出来,而不是领域概念和用例。

标签: asp.net-mvc design-patterns domain-driven-design inversion-of-control onion-architecture


【解决方案1】:

OA 可以被认为是 n 层架构 + 依赖注入——所以如果没有 IOC,你将很难实现 OA。

关于使用任何内层的外层,我个人在这一点上不同意巴勒莫。我认为应该限制外层与下一层一起工作(重申:不应允许外层绕过一层)。我曾经在 twitter 上问过他这个问题,他说数据访问实现代码与表示层一起工作可能不是一个好主意(记住实现代码位于他架构的外缘)。

我认为巴勒莫为绕过层腾出空间正是因为他希望能够在控制器中操作域模型域服务。据我了解领域驱动设计,领域服务仅在逻辑不完全适合领域模型时创建。如果是这样的话,那么域服务和域模型并不是真正的 2 个独立的层。相反,最好将它们视为单个业务层。如果它们都是同一层,那么是否可以在 Controller 中同时使用它们的问题就会自行解决。那么你可以毫无矛盾地说外层应该被限制为与洋葱中的下一层对话。

【讨论】:

  • 感谢您的意见,克里斯。假设我们的一些领域模型逻辑丰富,不需要服务层,你会不会总是通过接口和IOC将领域模型注入表示层而不是参考具体的实现?
  • 我自己不是DDD从业者,所以很难回答。我的直觉告诉我,我可能会注入一个接口来检索域对象。如果你真的觉得不需要那个接口,那么下一个问题就变成了“你的领域模型有依赖关系吗?”如果是这样,是的,你应该注入它。否则,您的控制器必须知道如何构建域模型,这意味着它必须了解更多关于其依赖关系的信息。
  • DK Mulligan 在他的blog post 上使用的图表可能很有用。
  • 我认为能够从外层访问所有内层的想法是限制耦合并展平依赖关系图。如果 A 层依赖于 B 层,而 B 层又依赖于 C 层,那么 A 就有一个很大的依赖链。但是如果A层真的不需要B层的任何东西,只是用来间接使用C层,那为什么不让A层只依赖C层,这样就减少了依赖链。这样,如果您换出 B 层或更改其中的内容,则无需触摸 A 层或 C 层,它们仍然可以工作。我也想不出有什么负面影响。
  • 当 UI 代码从应用程序的最内层绑定到实体时,我遇到了很多问题。出于这个原因,我倾向于将我的 UI 代码绑定到一个 API,该 API 的设计更多地围绕 SOA 或功能值而不是 DDD——即使该 api 没有作为 Web 服务公开。如果您没有遇到这些问题,您应该继续做对您和您的团队来说最容易理解和维护的事情。
【解决方案2】:

首先,请记住,Onion Architecture (OA) 与应用程序设计风格无关,因此没有什么能阻止您将域注入 UI。其次,链接的文章指出 IoC 是核心,所以你不会想尝试没有它。我还推测您在谈论您的域实体 - 那些在您的域中具有数据/状态的东西。

OA 是关于保护您的域(业务规则、实体等)免受基础设施变化的变幻莫测,而不是相反。通过使用接口访问您的域,您所购买的只是额外的代码和间接。问问自己 - 如果我的域发生变化(您业务的核心),期望我的用户界面不会是否现实?换句话说,如果您的业务规则发生变化,如果涉及添加或删除字段或整个业务线,用户可能会希望在 UI 中看到这一点。

现在问这个问题的反面 - 如果我从 Oracle 更改为 NoSQL,我的域代码会更改吗?注入您的基础设施负载服务意味着给您“否”的答案。这大概意味着更容易维护和更稳定的代码。

因此,总而言之,除非您需要在域实体上隐藏逻辑,或者存在令人信服的架构原因(例如,您将这些逻辑从服务器扔到远程客户端,或者您想要添加 UI - 影响验证或标签显示的属性的特定属性),您应该继续在“应用程序/UI”层中直接引用您的具体域实体。

【讨论】:

    猜你喜欢
    • 2023-04-02
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 2015-05-30
    • 2015-04-10
    相关资源
    最近更新 更多