2

我正在开发促销系统,我刚刚踩到了一些可能用状态机模式处理的东西,但我还没有使用状态机的经验。也许状态机在这种情况下完全没用:) 所以我有一个促销活动,它有一定的持续时间,一些指定的客户、产品、折扣等。每个促销活动也有它的状态。大约有5个州。状态之间的转换是严格定义的——不可能直接将状态 1 更改为状态 3——用户必须先将状态更改为 2。有一些限制,例如“促销处于状态 3-5 时无法添加更多产品”。或者像“只有超级用户可以在状态 3-5 时编辑促销成本”之类的限制。

我刚刚阅读了有关http://www.codeplex.com/SimpleStateMachine的信息,但我不确定对于这种情况是否不太复杂。我可以使用以下方式处理服务层中的状态逻辑:

if (promotion.state == statesRepository.GetState3() && false == loggedUser.IsInRole("superUser")){
   throw new PromotionStateException("user not allowed to edit promotion in this status");
}
...

或者

public void ChangePromotionStatus(promotion, newStatus){
  if (promotion.Status == status1 && newStatus != statesRepo.GetState2()){
    throw new StateTransitionException("unable to change from status 1 to " + newStatus);
  }
}

但我不喜欢这种代码 - 必须有一些更好的方法:) 有人有建议吗?当然,我可以分离关注点并开发诸如 PromotionStatusChangeReviewService、PromotionEditPermissionService 等服务以减少代码耦合,但目前可能有一些更好的解决方案我看不到。

4

2 回答 2

4

五个状态对于状态机来说并不太复杂,但我认为你会通过尝试对一些转换进行特殊或显式处理而遇到一些问题。这里有一些提示:

  • 除非您可以以有意义的方式标记状态,否则状态机没有帮助。“状态 3”没有任何意义;您需要将其称为有用的名称,例如“已升级”、“活动”、“已完成”等。

  • 状态机模式的一部分假设您有一个分离的实体,它了解状态以及如何在它们之间转换。例如,您不应该使用示例中的方法ChangePromotionStatus(),如果不应该允许该状态,它就会爆炸。状态机应该简单地防止不能发生的转换。

  • 如果可能的转换数量很少且定义明确,并且标记它们是有意义的,我还建议命名转换。如果转换都做同样的事情但方式略有不同,这可能特别有用。

于 2009-03-23T14:23:15.930 回答
2

John 一针见血——您希望您的流程(使用状态机建模)与您的域实体分离。您的域实体可能不应该直接知道它们正在用于状态机,状态机将根据某些事件管理将它们从状态转换为状态的工作,但它们理解它们所处的每个状态的业务含义,并能够执行或应用与这些州相关的业务规则。

理想情况下,适合由状态机管理的域实体将具有某种状态,充当状态机的状态,并将引发可由状态机用来确定何时适合转换的事件.

但是,如果您的状态确实是完全顺序的 - 即它们总是走 abcde 或向后和向前恰好一步,我不确定状态机是否有意义,因为选择下一个状态不需要特殊的上下文- 你只能后退或前进,所以任何有序的状态列表(例如枚举)加上 Next/Previous 逻辑就足够了 - 但现实世界的进程很少是严格线性的,即使它们乍一看可能看起来很脸红.

于 2009-03-27T19:33:01.973 回答