【问题标题】:Should logic regarding an user's actions history be placed inside or outside the domain?关于用户操作历史的逻辑应该放在域内还是域外?
【发布时间】:2014-06-06 00:05:06
【问题描述】:

假设这个写入模型有 4 个聚合:

应用程序需要阻止/禁止在 x 天间隔内访问商店超过 x 次的任何客户。

我应该把这个逻辑放在哪里?如果它应该在域层中,我应该为这个逻辑创建一个 ClientStoreVisitHistory 实体吗?或者我应该把这个逻辑放在域之外?

非常感谢任何帮助。

【问题讨论】:

  • 客户为什么要光顾实体店?整个应用程序旨在解决什么业务问题?
  • @hippom 该模型只是显示我的问题所在的示例。无需考虑其他行为……我的主要问题是需要了解客户进行的所有 StoreVisits 的行为/逻辑,然后将该历史记录与商店的限制进行比较。这应该在域内还是在域外?用完整的访问历史填充聚合似乎不合适。这可以通过对持久化历史数据的简单查询来解决。
  • 我认为该应用程序提供了一些服务,而不仅仅是限制访问。在这种情况下,至少有两个域,一个是针对核心业务关注点的核心域,另一个针对身份和访问。你上面的模型应该放在第二个。现在让我们回到您的问题:逻辑在作为核心域基础设施的身份和访问域中(因此它在核心域之外)。
  • 实际上域中的所有内容都与客户端/商店实体相关联。我正在考虑这样做: StoreVisitLimitSpecification (1:1 with store) 在 store aggregate 内。 StoreRecentVisitActivity 实体聚合关联到 StoreVisitLimitSpecification 。在 StoreVisitLimitSpecification 内部检查访问是否生成阻止/禁止:如果进行 StoreVisit 的客户端已经在 StoreRecentVisitActivity 中出现 x 次,则阻止他。你怎么看 ?附: : StoreRecentVisitActivity 将在 x 天限制期内保存一些访问的参考。
  • “阻止”是指拒绝访问(如http访问)还是只是逻辑约束?

标签: oop architecture uml domain-driven-design cqrs


【解决方案1】:

您所说的限制显然属于问题域,应该在那里建模。我不会为此创建任何新类,而是将此逻辑放在对象 StoreVisit 的构造函数中。由于它直接处理对 Store 的访问并接受两个参数(客户端和存储),因此您无需以这种方式添加任何新的依赖项或新类,并且可以访问所有需要的信息来评估访问。

请注意...如果您对问题域的类进行建模,我建议不要对实体的 id 进行建模(假设它们并且模型更清晰),以更好地指定关联并添加一些方法。按照您的做法,它看起来更像是数据库设计。

更新(在 cmets 之后)

如果需要多个属性(当前为 clientVisitsLimit 和 daysIntervalForclientVisitsLimit),则单独的“StoreVisitLimitSpecification”实体是有意义的。如果您期望这个实体在未来增长,那么将它作为一个单独的类是合理的。如果您希望当前版本稳定,那么将所有内容集中在一个类中也是可以接受的。

关于以下内容:

StoreRecentVisitActivity 实体聚合关联到 StoreVisitLimitSpecification 。 StoreVisitLimitSpecification 内部 检查访问是否产生阻止/禁止:如果客户端进行了 StoreVisit 已经在 StoreRecentVisitActivity 然后阻止他。

  • 我认为这不是一个好主意。 StoreRecentVisitActivity 类是完全多余的,因为 StoreVisit 已经保存了访问历史。我们希望保持我们的领域模型简单而小巧
  • 我肯定会避免检查 StoreVisitLimitSpecification 中的阻止/禁止。顾名思义,这是一个助手,规范类,应该是完全被动的,没有任何逻辑,只能从外部查询。因此,它本身不应对任何形式的验证负责。如前所述,我会将这个逻辑放在 StoreVisit 构造函数中,或者最终(如果非常复杂)放在 StoreVisit 的单独帮助器类中。它可以通过 Store 类从那里获取(因为它属于 Store)。

这是我对域模型的建议:

这是一个显示创建新 StoreVisit 过程的序列图:

我觉得它紧凑、简单、清晰。 StoreVisit 拥有访问历史的所有数据,因此无需其他依赖类即可访问它。 Store 持有对 LimitsSpec 的引用,并根据 StoreVisit 的请求提供它。

【讨论】:

  • 感谢您的回答。提及即使客户超过限制访问也是有效的。如果他超出限制,我只是将他添加到黑名单中。检查 StoreVisit 中的访问历史似乎不是一个好主意,特别是当我需要检查商店访问限制时。此逻辑应位于单独的对象中。同样关于 id,如果有 GUID 或其他东西来区分对象,则使用持久层会更容易(使用跨越属性的标识符会使整个问题过于复杂)。附: : 阅读我上面的 cmets
  • (添加到答案文本的 UPDATE 部分)
  • StoreVisit 不保存访问历史记录 :) 。 StoreVisit 只是一次访问,它有助于跟踪访问:)。这不是参观收藏,只是参观。访问集合可以在商店聚合或客户端聚合内。也可能有数万次访问,真的需要从一个聚合中的持久层调用所有历史记录,什么时候可以通过读取持久存储来完成?您也可以使用规范进行验证,检查新访问是否在商店限制的天数间隔之间,取决于您如何查看它。
  • 这里我们应该区分两种不同的视角,对应两种不同的模型:概念域模型和物理实现模型。我只说第一个。 Cenceptually 只有“访问”的概念,“访问历史”只是许多旧“访问”实例的集合。然而,在物理级别上,您可以决定对域进行非规范化并优化数据库的性能,因此将此概念拆分为两个数据库表 - 例如“访问”用于保存当前访问(或最近 10 次),“访问历史”用于保存旧访问。
  • 我知道有两个概念。正如我的问题所述,使用持久对象历史的逻辑应该在域内还是域外?例如,聚合的唯一性应该在命令对象 (cqrs) 的域之外。这种独特性与所有持久聚合的历史相关。我会更多地考虑这个黑名单案。谢谢你的回答。 +1 并接受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-28
  • 2014-12-09
  • 2013-12-09
  • 1970-01-01
  • 2012-07-19
  • 2017-03-27
相关资源
最近更新 更多