【问题标题】:Considering the following architectural changes and need some advice (Domain Entities, DTO, Aggregates)考虑以下架构更改并需要一些建议(域实体、DTO、聚合)
【发布时间】:2012-09-29 07:09:22
【问题描述】:

大约一年前,我建立了一个由 ASP.Net MVC 3(现在)表示层、应用程序层、域层和基础设施层(横切材料和数据)组成的解决方案。我决定将域模型与域逻辑保持在一个单独的项目中,并通过传递域实体而不是 DTO 对表示层使用一种轻松的方法,因为我们现在实际上只有一个前端。

我们将很快为分布式层提供服务,除了我们的主网站,我将在那里使用 DTO,但我也在考虑在主网站中使用 DTO。我还想知道我是否应该费心在域层(IRepository、IUnitOfWork、实体/值对象超类型等)中分解框架代码。那么在这里,让我列出我需要反馈的问题:

1) 我非常努力地避免没有一个贫乏的领域模型,并且还注意特定于演示问题的行为。所需的大多数业务计算都在域实体上,表示层可以直接调用此行为还是应该调用应用程序服务,然后调用域实体?这向我表明,没有理由让表示层知道域实体,而是可以使用 DTO。或者,我可以让 DTO 公开这些行为,但我觉得我在抢劫域实体。所以我猜这是最好的 3 个选项(直接调用丰富的域对象、服务层或 dto)?

2)现在我有一个领域项目,它具有领域服务、规范和逻辑,由应用层和单独的领域模型项目(由表示层和应用层使用)编排。我这里还有通用存储库和工作单元模式的框架接口。我是否应该将框架内容拆分到一个单独的项目中,然后将其余部分合并到一个项目中?

3)我想将我的领域层重新组织成聚合,现在所有的领域模型都是由模块组织的,基本上每个模块的所有类型都在一个命名空间中。通过聚合来组织实体、值对象、服务和其他东西会更好吗?

4) 对于基本上是 .net 框架助手库类型的基础设施服务,我应该使用分离接口模式吗?例如配置对象或验证运行器?这样做有什么好处?

5) 最后,我见过的使用域实体接口的例子并不多。由于依赖的原因,我几乎所有的对象都喜欢传递接口,它使测试变得更加容易。使用接口而不是混凝土是否有效?我应该提到我们使用 EF 4.3.1(即将升级到最新版本),我似乎记得 EF 在使用接口或其他东西时遇到了问题。我应该公开接口而不是域实体吗?

非常感谢您。

项目结构:

Presentation.Web | | |应用 | | | Domain.Model - 域 (基础设施.数据、基础设施.核心、基础设施.安全)

说明: Presentation.Web(MVC3 网络项目)

应用 -- 协调域层并响应来自表示层的请求的服务层(获取此更新)。这是按模块组织的,例如,如果我有一个客户模块,我将拥有 Application.Customer,其中包含所有应用程序服务

域 -- 包含域服务、规范、计算和其他不作为域实体行为公开的域逻辑。例如,涉及多个域实体的计算,这些实体公开为应用层调用的域服务。 -- 还包含规范框架的框架代码和通用存储库和工作单元模式的主要接口。

域.模型 -- 包含域实体和枚举。按模块组织。例如,如果我可能有一个客户模块,其中包含客户实体、客户订单实体等。这是从域项目中分离出来的,以便应用程序和表示层可以使用这些对象。

基础设施.安全 -- 身份验证和授权的安全基础设施

基础设施.核心 -- 由多个层(验证器、日志记录、配置、扩展、IoC、电子邮件等)使用的横切内容。大部分项目都依赖本项目中的接口(domain.model 除外)提供基础设施服务。

基础设施.数据 -- 通过 LINQ 和 EF 4.3.1、映射层、工作单元实现的存储库实现。接口在域项目中(分离接口模式)

【问题讨论】:

  • (1) 你的“领域模型”和“领域逻辑”有什么区别?每个项目中有什么,你如何理解分离。你从他们的分离中得到什么好处? (2) 你所说的“模块”是什么?你的意思是VB模块? (3) 你的 DTO、你的接口和你的领域模型对象有什么区别?您可以发布一个示例,并注释每个组件来自哪个项目吗?这将使您更容易理解您的设计。我们可以为您提供帮助,但我们猜测的太多了。
  • 午饭回来后我会尝试添加项目结构。不过,在我做到这一点之前,我会看看我是否可以更好地解释事情。域模型和域逻辑之间的区别在于,域模型只是实体,我所说的域逻辑是诸如域服务和工作流之类的东西,它们涉及的不仅仅是一个实体,或者不作为行为暴露在实体上。
  • “模块”对我来说是系统的垂直部分。我们的系统基本上是一个“模块”的集合,每个模块都有一个子系统。如果您将 MS Office 视为一个应用程序,那么 Outlook 将是一个模块,而 Word 将是另一个模块。
  • DTO 和接口与我们的领域模块对象的区别在于,DTO 是在层之间传输数据的哑对象(扁平模型),领域对象具有丰富的行为和相互关系,而接口只是是客户(表示层)也可以绑定的域对象的抽象,而不是直接绑定到域对象(程序到接口)。我会尽快发布项目结构更新。谢谢

标签: entity-framework domain-driven-design dto aggregates


【解决方案1】:

1) 首先,确定你的主网站是否真的需要使用应用层。恕我直言,如果您的应用程序服务和您的主网站位于同一 Web 服务器上,那么您应该评估潜在的性能损失是否值得让您的主网站在可以直接调用域对象时调用应用服务器方法。但是,如果您的应用程序服务器肯定在另一台服务器上,那么是的,您应该让应用程序服务器调用您的域对象,并且只在它与您可能拥有的任何表示层(包括您的主网站)之间来回传递 DTO。

2)这实际上是一个关于组织偏好的问题。两者都是有效的。你选择。

3) 关于组织偏好的另一个问题。我个人首先通过限界上下文组织我的代码。然后,我在它们的正下方有实体和聚合根。然后,我有枚举、存储库(接口)、服务(接口)、规范和值的文件夹。命名空间不反映最后一个有界上下文文件夹之后的这种组织结构。但是,同样,您应该以最适合您查看代码的方式来执行此操作。

4) 这是一个实现问题。如果我认为将来很有可能需要更换实现,我个人只会将实现问题分解为接口。话虽如此,我通常将我的帮助程序库组织到特定的基础设施上下文中(例如 MainContext.Web.MVC.Helpers 或 MainContext.Web.WebForms.Helpers。)这些很少改变,我还没有遇到我需要的实例完全换掉实现。

5) 据我了解,为您的域实体使用接口而不是具体是完全有效的。话虽如此,我还没有遇到过我的域实体需要不同实现的情况。我什至能想到的唯一原因是,如果您需要更改一个应用程序的业务逻辑,但保留使用原始业务逻辑的旧应用程序。如果您的业务对象是该领域的良好模型,我无法理解您实际上会遇到这个问题,但我已经看到人们只是为了抽象而这样做的示例。恕我直言,这不值得额外的编码工作,但如果它让你内心感觉良好或者你获得了一些实际的好处(例如,使测试更容易),那么你没有任何理由不能抽象出你的域实体。话虽如此,域服务和存储库肯定应该有合同,允许您更换它们的实现。

答案 5 源于应用程序是选择实现的人的想法。如果您正在尝试实现洋葱架构,那么您的应用程序将为所有内容(存储库、域服务和其他抽象的实现问题)选择具体的实现。我看不出它为什么不能直接使用域聚合,因为它们是域模型的具体表示。 (注意:所有实体都应该封装到聚合中。应用程序永远不能持有对上下文下不是聚合的实体的引用)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2012-01-19
    • 2021-05-22
    • 2012-02-02
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多