大约一年前,我设置了一个解决方案,包括ASP.Net MVC 3(现在)表示层,应用层,域层和基础设施层(横切东西和数据)。我决定将域模型保留在与域逻辑不同的项目中,并通过传递域实体而不是DTO来使用放松的方法来表示层,因为我们现在只有1个前端。
我们将很快为一个分布式层服务,除了我们的主网站,我将在那里使用DTO,但我也考虑在主网站上使用DTO。我也想知道我是否应该打破域层中的框架代码(IRepository,IUnitOfWork,Entity / Value对象超类型等)。那么,让我列出我需要反馈的问题:
1)我非常勤奋,没有贫血的领域模型,也注意到特定于演示问题的行为。所需的大多数业务计算都在域实体上,表示层是否可以直接调用此行为,还是应该调用应用程序服务然后调用域实体?这将告诉我,没有理由让表示层知道域实体,而是可以使用DTO。或者,我可以让DTO暴露这些行为,但后来我觉得我正在抢夺域实体。所以我猜这是3个选项(直接调用富域对象,服务层或带行为的dto)哪个最好?
2)现在我有一个域项目,它具有域服务,规范和逻辑,由应用层和域模型的单独项目(由表示层和应用层使用)编排。我也有通用存储库和工作单元模式的框架接口。我应该将框架内容分解为一个单独的项目并将其余项目合并到一个项目中吗?
3)我想将我的域层重新组织成聚合,现在所有的域模型都是按模块组织的,基本上每个模块的所有类型都在一个命名空间中。通过聚合来组织实体,价值对象,服务和其他东西会更好吗?
4)我应该对基本上是.net框架帮助程序库类型的基础结构服务使用分离接口模式吗?例如配置对象或验证运行程序?这样做有什么好处?
5)最后,我见过的很多例子都没有使用域实体的接口。几乎我拥有的每个对象都因为依赖性原因而更喜欢传递接口,这使得测试变得更加容易。使用接口而不是混凝土是否有效?我应该提一下,我们使用EF 4.3.1(很快升级到最新版本),我似乎记得EF在使用接口或其他东西时遇到了问题。我应该公开接口而不是域实体吗?
非常感谢你。
项目结构:
Presentation.Web | | | Application | | | Domain.Model - Domain (Infrastructure.Data, Infrastructure.Core, Infrastructure.Security)
说明: Presentation.Web(MVC3 Web项目)
应用 - 服务层,用于编排域层并响应来自表示层的请求(获取此更新)。这是由模块组织的,例如,如果我有一个客户模块,我会有Application.Customer,那将是所有的应用程序服务
域 - 包含域服务,规范,计算和其他未在域实体上作为行为公开的域逻辑。例如,涉及多个域实体的计算,这些域实体作为域服务公开,供应用程序层调用。 - 还包含规范框架的框架代码以及通用存储库和工作单元模式的主要接口。
Domain.Model - 包含域实体和枚举。由模块组织。例如,如果我可能有一个客户模块,其中包含客户实体,客户实体等。这将远离域项目,以便应用程序和呈现层可以使用这些对象。
Infrastructure.Security - 用于身份验证和授权的安全基础架构
Infrastructure.Core - 多层使用的交叉填充内容(验证器,日志记录,配置,扩展,IoC,电子邮件等)。大多数项目依赖于此项目中的接口(domain.model除外)用于基础结构服务。
Infrastructure.Data - 通过LINQ和EF 4.3.1,映射层,工作单元实现的存储库实现。接口位于Domain项目(分离的接口模式)
中答案 0 :(得分:1)
1)首先,确定您的主网站是否真的需要使用应用层。恕我直言,如果您的应用程序服务和您的主要网站在同一个Web服务器上,那么您应该评估潜在的性能损失是否值得让您的主网站调用app服务器方法,直到它可以直接调用域对象。但是,如果您的应用程序服务器肯定在另一台服务器上,那么您应该让应用程序服务器调用您的域对象,并在它与您可能拥有的任何表示层(包括您的主网站)之间来回传递DTO。
2)这实际上是关于组织偏好的问题。两者都有效。你选择。
3)关于组织偏好的Anoter问题。我个人首先按有界上下文组织我的代码。然后,我直接在它们下面有实体和聚合根。然后,我有枚举,存储库(接口),服务(接口),规范和值的文件夹。名称空间不会反映此组织结构超过最后一个有界上下文文件夹。但是,再一次,你应该以最适合你看待代码的方式来做到这一点。
4)这是一个实施问题。我个人认为,如果我认为将来需要更换实现的可能性很大,我只会将实现问题分解为接口。话虽这么说,我通常将我的帮助程序库组织到特定的基础结构上下文中(例如MainContext.Web.MVC.Helpers或MainContext.Web.WebForms.Helpers。)这些很少改变,我还没有遇到我需要的实例完全交换实现。
5)根据我的理解,为您的域实体使用接口而不是混凝土是完全有效的。话虽这么说,我还没遇到我的域实体需要不同实现的情况。我甚至可以想到的唯一原因是,如果您需要为一个应用程序更改业务逻辑,而是使用原始业务逻辑保留较旧的应用程序。如果您的业务对象是域的良好模型,我无法理解您实际遇到此问题,但我已经看到人们为了抽象而这样做的示例。恕我直言,这不值得额外的编码工作,但如果它让你感觉良好的内部或你得到一些实际的好处(例如,使测试更容易),没有任何理由你不能抽象出你的域实体。话虽这么说,域服务和存储库肯定应该有合同,允许你交换他们的实现。
答案5源于应用程序是选择实现的人的想法。如果您正在尝试实现洋葱架构,那么您的应用程序将选择所有内容的具体实现(存储库,域服务和其他抽象实现问题)。我认为没有理由不直接使用域聚合,因为它们是域模型的具体表示。 (注意:所有实体都应该封装成聚合。应用程序永远不能在上下文中保存对不是聚合的实体的引用)