如何管理域模型或数据访问模型或数据传输模型

时间:2016-12-30 08:31:20

标签: c# domain-driven-design

在DDD中,有许多模型:

  • 域模型,用于业务或应用层。
  • 数据访问模型,用于数据访问或数据存储库层。
  • 数据传输模型(DTO),用于表示层。

由于他们,缺点提出:

  • 他们违反DRY原则,因为他们之间存在许多重复的字段而无法避免。
  • 他们需要对不同层之间的转换进行大量烦躁的映射。

我们如何减少烦躁的模特?

4 个答案:

答案 0 :(得分:6)

最终,这是关于选择你的战斗。域驱动解决方案的主要考虑因素之一是它专注于域的隔离和封装。这意味着,在这个前提下,您不会希望将其用作每个项目中的方法。您需要具有您尝试减少的固有复杂性,并且您可以通过独立地模拟业务需求和应用程序需求来实现这一点。这意味着您不是在创建单个系统,而是使用完善的子系统(您的域)创建一个或多个系统(您的应用程序或应用程序)。

就个人而言,我没有您在我的任何项目中描述的三种类型的数据承载类。相反,我只有我的域模型和基于每个不同UI要求的视图模型表示。我发现需要一组单独的持久化类是多余的。有几种方法可以消除对持久性类的需求,例如具有代码优先EF的POCO,对象数据库/ NoSQL,以及读取模型和写入模型的分离。在大多数情况下,我个人选择最后两个的组合。

域和应用程序/ UI之间的转换层是我发现需要的东西,因为"真相"域代表的是绝对可靠的。但是,为了获得域中的可用接口,应用程序有时会对域具有额外的或不同的要求。这意味着这个转换层不仅仅是关于字段映射,而是关于不同概念的封装和使用场景的隔离。

由于域名应该完全不知道如何使用它,这意味着有一个要求用于翻译,并且不应该尝试从系统中解决。我见过的人直接在UI中使用他们的域类作为实际模型,这比创建翻译层更令人发指(在我看来)。你只是从翻译的角度看待它,但要记住它也是关于隔离的。在翻译中可以有效地拦截新概念的引入,现有概念的更改以及域内的其他更改,以防止在UI中产生影响,反之亦然。

这听起来微不足道,但在企业环境中,不仅仅有一个应用程序利用域,而是多个应用程序并不罕见。考虑您的域服务于桌面应用程序,Web应用程序和REST API的可能性。其中每个都有自己的特定应用程序要求,这些要求与业务要求分开。他们也可能希望以不同方式表示域名。这意味着它们中的每一个都可能具有不同的验证要求,对您的域的不同视图以及独特的应用程序功能。无论如何,域名仍然高兴地忘记了这一切。您必须针对每个域进行不同的翻译。

如果您发现您的模型看起来与您的域名完全相同,其中大部分是一对一映射,那么您可能需要退一步寻找可能正在发生的其他一些问题。我发现大量的奇异字段的双向映射是代码气味。并非总是如此,但通常情况下,这是贫血领域模型的早期迹象。我个人甚至在我的域模型上强制执行体系结构要求,例如要求属性是只读的(强制它们通过现有数据的构造函数设置并通过类上的方法进行更改)等。这是公平的编写体系结构单元测试的简单方法,它将反映您的域类,以检查它们是否存在违反此类规则的行为。但是,关键是如果您发现翻译是您的痛点,请确保您的域模型不仅仅是作为数据容器。贫困领域模型在DDD实施中是一个非常常见的陷阱,并且对于贫困领域模型,DDD方法实际上几乎没有什么好处,因为您将权力和责任从应该强制执行的地方带走。 / p>

业务要求应反映域的需求,这与域的使用模式不同。理想情况下,您应该告诉域您要如何更改其状态,域应该应用域逻辑来允许或禁止这些更改。如果您发现自己为域的一部分提取完整的域模型表示,将整个事物转换为模型或DTO,修改该模型或DTO,将其转换回域表示,然后将整个事物发送回去,你可能有更大的问题。

答案 1 :(得分:2)

您可能想要了解您对DRY的理解。一个很好的起点是DRY is about Knowledge - Matthias Verraes(2014)。

您可能还想看看Gary Bernhardt的2012年演讲Boundaries

关键思想是 - DTO模型是域模型和表示组件之间的API契约。它使我们可以自由地积极更新/改编/改进领域模型,而不会破坏现有的演示组件。

类似地,数据访问模型是域和表示组件之间的API契约。这不仅意味着域和持久性之间的接口是稳定的,而且它还提供了域模型的当前实现(今天写入数据)和域的 future 实现之间的稳定契约。模型(明天回读相同的数据)。

答案 2 :(得分:2)

不,模型不多。同一模型有多种表示形式。这种区别非常重要。

在域模型中,实体负责确保其状态是不可行的。例如,除非同时设置ApprovedAt,否则不能设置ApprovedBy属性。这通常是通过向实体添加 行为 来完成的。我这样做是通过始终将所有属性设置器设置为私有,然后每次实体需要更改状态时添加方法。

DTO负责在应用程序边界之间传输状态。但是当您正确执行DDD时,您不希望将域实体传输到客户端。您希望它在服务器中保持安全。因此,DTO的作用更为重要。您甚至可能为同一实体拥有多个DTO。例如,我可能有一个UserListDTO,其中包含仅列出实体的子集,也可能是UserDetailsDTO,它是为用户详细信息页面设计的。对于写入,您只需传输变异状态或发送受命令影响的DTO(ApproveUserDTO)。

最重要的是,域实体不能以某种方式被设计为能够持久化它。这就是我们拥有数据实体的原因。它的设计将使一切都能以有效的方式持久化。用户可能拥有一个名为User的数据实体和一个名为UserField的数据实体,具体取决于域实体设计。

结论是,如果你的模型看起来完全一样,那你就做错了(从DDD的角度来看)。

答案 3 :(得分:2)

<强> 1。这不是关于域驱动设计

分离模型带有您祖先的n层建筑风格。它可以追溯到DDD出现之前很久。

<强> 2。您不必拥有那么多模型

如果您的应用程序足够简单,您可以放弃其中一些。

首先想到“数据访问模型”。这只是DDD随身物品的最新成员。但是你可以做得不那么好,对你的领域模型产生轻微的影响。

猜猜看,您甚至可能发现根本不需要丰富的域模型......有些应用程序的效果最好就像CRUD一样。

如果你发现“易怒”的东西,摆脱它,看看自己有什么好处/缺点。守则警察不会来敲你的工作场所并锁定你所谓的简单性而不是所谓的正统观念。

相关问题