猿问

DDD - 在拥有映射器类时不暴露 getter

我最近阅读了很多关于 DDD 的文章。我有一些基本知识(并在实践中使用过),但现在我决定(几乎)100% DDD。当然,我马上就遇到了问题。

我为每个模块(功能)设置了 3 层:应用程序、域和基础设施。我使用六边形架构模式,这基本上意味着我在域类中获得了我的核心逻辑,应用层使用它(但域层根本不知道应用层),基础设施从域(数据库存储库)和一些接口实现我的端口从应用层等

现在,当我在应用程序服务中处理一些用例时,我必须使用我的根聚合并执行一些逻辑,最后将它映射到一些用于 UI 的 DTO。问题是要执行这样的映射,我必须为我的大多数属性提供 getter/setter,这会杀死我。我想通过提供大量业务方法和很少的 getter/setter 来避免贫血模型。

我可以看到 2 个解决方案:

  • 在我的域层中引入 DTO,这又是 DDD,并且在我的实体中有 toDTO() 方法

  • 提供 getter/setter 并仅在映射器中使用它

任何其他解决方案,你们如何处理应用程序中的此类常见问题?我知道在现实中很难做到纯粹的 DDD,不遵循所有规则也可以,但我注意到尽可能少的 getter/setter 对我的设计有很大帮助,但同时很明显 DTO 不属于域。


qq_花开花谢_0
浏览 198回答 3
3回答

SMILET

Vaughn Vernon 在红皮书的第 14 章(应用程序)中处理了这个问题,在“用户界面”部分(第 512 页)中,他公开了一些替代方案:托斯调解人域有效载荷对象状态表示用例优化存储库查询(对 cqrs 关闭)数据转换器希望能帮助到你。

慕少森

问题是要执行这样的映射,我必须为我的大多数属性提供 getter/setter,这会杀死我。是的 - 我为此斗争了很长时间。真正的答案是没有魔法。如果您希望聚合有用,您需要能够以某种方式从中获取信息。只写数据库不是很有趣;如果界面上没有可用的查询,那么首先将信息放入事物中就没有多大意义。从聚合中获取值的域特定查询是可以接受的。关键限制应该不可能通过操作返回值来更改聚合的状态。所以我们倾向于返回没有修改器的对象,或者这些对象的副本。我们不应该鼓励消费者查询我们,对查询结果执行一些操作,然后根据这些操作的结果选择命令的习惯用法。// 不要这样做: int x = oX();&nbsp;x = x + 1;&nbsp;年(x)您可以做一些事情,使代码整体看起来“更干净”。1) 让聚合响应带有值对象的查询,然后查询这些值对象以获取构建 DTO 所需的信息。2)将工厂方法传递到聚合中以获取您需要的数据<T>&nbsp;T&nbsp;query(API<T>&nbsp;api)API<T>聚合可以与之交互的建造者/工厂事物在哪里。3)有两个由聚合实现的独立接口(一个用于查询,一个用于命令),并且只允许调用者访问他们需要的接口。4) 有一个查询点从聚合中获取“当前状态”,然后从中构建其他所有内容。

隔江千里

应用 CQRS,您可以避免在 AR 中使用吸气剂。此外,您甚至可以将 AR 中的属性数量减少到仅需要满足某些不变量的属性。让我更好地解释一下。CQRS(命令查询职责分离)完全区分了你的应用程序提供的命令和查询操作。命令操作通过执行一些用例来更改应用程序的状态。执行命令的结果是一个域事件,其中包含更改的信息。然后,领域事件(建模为 DTO)用于构建您的视图模型,其中包含您需要从查询中返回的所有数据。视图模型是一个易于序列化和通过网络发送的 DTO。因此,您的 Query 操作(用于使用信息填充 UI 的操作)甚至不会为您的 AR 注入水分。它们适用于您的视图模型,因此对其进行的任何更改都不会对您的 AR 产生任何影响。最后,正如我在开头提到的,大多数时候我们的 AR 中有大量属性只是为了将这些信息保存在我们的数据库中。但是,此信息从未用于满足任何不变量。例如,当我们保存用户的名称但我们再也不会在任何其他用例中使用该数据时。如果信息已经保存在域事件中并投影到您的视图模型中,您可以查询它,这样您就可以避免在 AR 中使用该字段,使它们尽可能保持干净。
随时随地看视频慕课网APP

相关分类

Java
我要回答