繁体   English   中英

如何使用 ddd 实现状态模式

[英]how to implement state pattern using ddd

我有一个关于状态模式以及如何使用 DDD 实现它的问题。 就我对状态模式的理解而言,该模式用于处理不同状态之间的转换,因此每个状态都有责任处理系统必须执行的操作才能转换到新状态。 为此,使用多态,每个状态都可以是它自己的一个类,它扩展一个基类,实现从一个状态到另一个状态的转换,遵循定义可能转换的图。

我一直在寻找有关如何使用 DDD 执行此操作的信息,并且在其他网站中,我发现了这个使用枚举的网站。

http://nurkiewicz.blogspot.co.uk/2009/09/state-pattern-introducing-domain-driven.html

使用枚举的原因是您可以将当前状态(在这种情况下是枚举的名称)保存到存储库,以便稍后重新创建您的聚合。 因此,按照状态模式定义,状态可以接收不同的参数(例如,字段的新值),因此上下文(在这种情况下是聚合)可以转换到新状态并更新其字段,从而使状态保持一致. 这意味着,状态将负责更新聚合的值。

我的问题是,这是正确的做法吗? 据我所知,在 DDD 中,聚合是知道其内部结构的聚合,每当必须更改聚合内的实体时,聚合必须公开一个方法,该方法稍后将调用该实体来更改其值。 通过这种方式,实体被封装在聚合内部,并且不能从聚合外部直接访问它们。

但是使用状态模式的这种实现,改变聚合的是实体(或值对象,我不知道如何调用状态)。 您甚至可以直接使用枚举并在其中调用传递您的聚合的操作,并且聚合将被更改。

关于这个的另一个问题是; 当您必须为聚合提供某些取决于当前状态的行为时,您在哪里进行实现? 在聚合内部,向状态的基类添加更多操作以检查状态是一种还是另一种? 或者在状态内部,因此状态使用聚合来调用它公开的不同方法以提供该功能? 第一种方法意味着,根据您拥有的状态数量,您将创建许多方法来检查您是否处于适合您的目的的正确状态。 另一个将暗示这再次是协调聚合必须调用其内部的方式的状态。

对不起,如果这个问题以前被问过。 我已经找了几天,但找不到与我在这里问的类似的东西。

提前致谢。

编辑:

抱歉回复晚了,我在假期。

在我的情况下,状态相当简单。 它们将反映比赛的不同状态(NEW、OPEN_REGISTRATION、CLOSED_REGISTRATION、IN_PROGRESS、FINISHED、CANCELLED)。 我想做的是按照我提供的链接中的方法对概念进行探索。

我的问题是:当聚合(上下文)必须做一些取决于状态的事情(比如注册一个玩家)时,你会在哪里保持这种逻辑? 在上下文中,首先检查状态类是否属于 OpenRegistrationState 类型? 或者在状态类中,在 OpenRegistrationState 中提供一个实现,将玩家存储到上下文中(该方法需要上下文和玩家作为参数)并从其他类中抛出和异常?

好像用了第二种方法,context里面的逻辑很简单,只需要调用当前状态就可以了。 问题是,当你有许多依赖状态来操作的不同方法时,你的状态类将有大量不同的方法,其中只有一两个会实现,而其他方法会抛出异常。 在这种情况下,我不知道忘记状态模式并仅使用枚举并在某些逻辑取决于当前状态时检查值是否会更容易。

状态模式的上下文表示一个对象的行为取决于它的状态,它的方法包含 if/then(或 case)逻辑,反映基于状态的条件。 该模式提供了这些 case 语句的替代方案。

解决方案是为每个状态创建类,实现一个公共接口。 依赖状态的操作从上下文对象委托给它的当前状态对象。 上下文对象指向反映其当前状态的状态对象。

因此,如果我理解您的问题,那么域对象(à la DDD)是上下文对象,您希望避免其中的大小写逻辑。 否则,您不需要状态模式(如果您愿意,您可以立即停止阅读,因为其余部分不适用)。

Craig Larman 的Applying UML and Patterns 3rd Edition 书中有一章是关于使用模式设计持久性框架的,还有一节是关于事务状态和状态模式的 我相信他的方法与DDD兼容,因为它已在此处定义 实际上,它是Scott AmblerPersistentObject 思想的变体

应用于持久域对象的状态模式

领域类有状态。 在这个例子中,状态是关于持久性的: NewOldCleanOldDirtyOldDeleteDeleted 有关详细信息,请参阅 Larman 的书。

我无法在上面的 PlantUML 图像上轻松注释的一些细节:

  • PObjectState抽象类具有每个方法(转换)的默认无操作主体
  • 实现,例如OldDirtyState.commit(...)处理基于状态的行为的实现。 对于持久性,这是有道理的,因为它们通常是与域逻辑无关的行为。 持久化对象的回滚基本相同。

Larman 有一个脚注指出“每当域对象类扩展技术服务类时,它应该暂停进行反射,因为它混合了架构问题(持久性和应用程序逻辑)。”

您没有使用具体示例来说明您想要建模的 State 究竟是什么,所以我不确定这个示例是否适用。

如果您的状态是一些横切关注点,在您的域对象中引入了不需要的耦合,那么您必须问自己一个更糟糕的问题:域对象中的案例逻辑,或不需要的耦合。 设计是权衡,你必须选择你的战斗。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM