我正在开发销售促销系统,我刚刚介绍了可能用状态机模式处理的东西,但我还没有使用状态机的经验。也许状态机在这种情况下完全没用:) 所以我有一个促销活动,有一些持续时间,一些指定客户,产品,折扣等。每个促销也有它的状态。大约有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等服务,以使代码更少耦合,但可能还有一些我目前看不到的更好的解决方案。
答案 0 :(得分:4)
对于状态机来说,五个状态并不复杂,但我认为你试图通过特殊或明确地处理一些转换来解决一些问题。这里有一些提示:
除非您能以有意义的方式标记状态,否则状态机无用。 “状态3”意味着什么;你需要称之为“推广”,“活跃”,“完成”等等。
状态机模式的一部分假设您有一个分离的实体,它理解状态以及如何在它们之间进行转换。例如,在示例中,您不应该使用类似ChangePromotionStatus()
的方法,如果不允许该状态,它会爆炸。状态机应该只是防止不能发生的转换。
如果可能的转换次数很少并且定义明确,并且标记它们是有意义的,我还建议命名转换。如果转换都以相同的方式但以稍微不同的方式进行转换,这可能特别有用。
答案 1 :(得分:2)
John击中头部 - 你希望你的进程(使用状态机建模)与你的域实体分离。您的域实体可能不应该直接知道它们正在状态机中使用,它将根据某些事件管理将它们从一个状态转换到另一个状态的工作,但是它们将 理解业务他们所处的每个州的含义,并能够执行或应用与这些州相关的业务规则。
理想情况下,适合由状态机管理的域实体将具有某种状态,充当状态机的状态,并将引发可由状态机用于确定何时的状态的事件。过渡是恰当的。
但是,如果您的状态完全顺序确实是正确的 - 即它们总是向后或向后转发一步,我不确定状态机是否有意义因为那里选择下一个状态不需要特殊的上下文 - 你只能向后或向前,所以任何有序的状态列表(如Enum)与下一个/上一个逻辑相结合应该足够 - 但真实世界的过程很少是严格线性的,即使他们看起来乍一看也是如此。