如何正确使用状态模式?

Iva*_*van 41 oop design-patterns

我在编程经历中遇到过一些状态模式的实现,并做了一些.我已经看到它们在各种场景中使用(主要是UI和解析).麻烦的是,所有这些都在快速发展的压力下变成了难以维护和可理解的代码块.我正在考虑重构其中一个,但我在网上找不到好的资源.在线状态模型有很多简单的例子,但我需要更深入的资源.

所以我在寻找:

  • 实现状态模式时常见的陷阱示例以及如何避免它们,
  • 正确完成状态模式的真实世界示例(如在某些开源项目/框架中)
  • 我们也欢迎有关国家模式的个人经历

感谢您的时间

oos*_*wal 25

@Ivan:Web上有许多可用于分层状态机(HSM)的资源.Miro Samek撰写了大量有关此设计模式的文章,并提供了大量有用的信息.

一些应该感兴趣的文章:

使用HSM而不是Mealy和Moore描述的平坦FSM状态图表的最大好处是层次结构创造了责任分离.子状态只需要处理它们明确设计要处理的那些条件 - 未处理的事件被传递到父状态,如果父状态没有明确地设计来处理它,那么它被传递到下一个更高的状态父母等.它允许您创建小型,可管理的状态机,每个状态机都有一个用途 - 一个可以放在一个对象中的状态机.随着新功能的添加,或者添加新类,他们只需要处理自己的小部分世界,并将未处理的事件传递给各自的父母.

正确实施后,您将获得一个具有低圈复杂度的强大程序,可以根据需要轻松修改或升级.


ora*_*ips 24

正如您可能已经阅读过的那样,当状态改变某个对象的行为时,状态设计模式很有用,该对象的组成包括该状态.这意味着State抽象类,接口或枚举类型的想法- 尽管取决于Duck Typing将要执行的语言- 定义任何常见行为和/或所需方法.

关键方面

在处理状态模式时,有两个关键方面需要考虑:枚举和转换.枚举仅仅意味着识别可能状态的集合(例如,一周中的几天),或者更抽象地表示状态的类型(即元状态),例如工作流引擎的开始,结束和中间.转换意味着决定如何建模运动通常通过捕获表格表示中的所有可能转换(即有限状态机)或使每个状态知道其可能的"转换"到其他状态来完成状态之间的状态.

通常,转换与元状态密切相关,因为在这样的动态系统中不可能提前知道所有状态和关系,其中可以在运行时添加新状态,从而可以添加转换.此外,通过转换方法,某些行为(例如通知)成为转换的一部分,而不是状态本身.

例子

有几种情况我已经研究或讨论过这是一个使用工具:

  1. 工作流程
  2. 电脑游戏对手AI
  3. 流程编排

工作流程,我的意思是像jBPM.像这样的系统关注的是在合适的时间对正确的人进行正确的关注.他们通常会发送大量电子邮件或其他类型的通知.而且,他们所代表的流程需要能够随着组织的变化而变化,而被管理的数据通常变化要慢得多.

电脑游戏对手AI是自我解释的.这不是我写过的东西,但在与那些人的谈话中,这些系统通常是自成一体的.换句话说,与工作流程不同,游戏通常没有改变用于控制计算机对手的过程的工具.

Process Orchestration与工作流程类似,但侧重于系统集成,而不是人员交互.的阿帕奇骡框架就是一个例子.这里state可以描述状态(例如,启动,进程,结束)和类型(例如ftp集成点,sql集成点).

结论

与其他答案不同,我认为状态封装是管理软件系统变更的绝佳方式.做得好,它促进了这些更改或使用户能够在运行时这样做.您需要权衡更多的灵活性,以换取更高的实现复杂性.因此,这种方法可能对购物车没有用,例如,行为可能是众所周知的并且不喜欢改变.另一方面,当过程发生变化时,它非常适合.


neu*_*uro 8

仅仅是我的2美分,状态模式总是变得难以维护,因为那些没有编码它的人很难理解.我通常回退到旧的标准函数/方法指针数组,就像我在旧的C体验中一样.您只需构建一个二维函数指针数组,其中包含行/列的状态/信号.更容易理解.你有一个管理它的类,你委托给其他类来处理复杂性......

MY2C

  • +1有趣的想法...你有样品吗? (2认同)

Gle*_*003 6

大多数情况下,状态模式设计中的状态处理的是一个状态(或状态的子状态),这使得它们更难维护.

如果一个州有任何选择,那么它主要处理一个以上的州.

我需要很多纪律来保持国家的清洁.

对此的可能解决方案是使更复杂的状态机本身(HSM).这使得它在更高层次上更具可读性,因为它必须处理更少的状态.