状态机和状态模式的实现有什么区别?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了状态机和状态模式的实现有什么区别?相关的知识,希望对你有一定的参考价值。
我想知道状态机是否只是工作中的状态模式,或者这两者之间是否存在差异?
我发现这个article with the bold title "the state design pattern vs state machine"但是在一天结束时他只说状态模式使状态机过时但后来没有描述状态机与状态模式的实现相比究竟是什么。
我向同事描述这种差异的方式是状态模式是许多独立封装状态的更分散的实现,而状态机更加单一。状态机的单一性质意味着单个状态将难以在不同的机器中重用,并且将状态机分解为多个编译单元更加困难。另一方面,这种单片设计允许更好地优化状态机,并允许许多实现在表中的一个位置表示所有转换信息。这尤其适用于负责状态机体系结构或功能的人员不熟悉其实现的编程语言的情况。请记住,许多工程和数学专业的学生都学过状态机,但很少或根本没有接受过教育。编程领域。与状态模式的页面和页面相比,向这些类型的人呈现转换,动作和警卫表要容易得多。
虽然这篇文章实际上是一篇很好的读物,但我在几点上不同意作者:
- “当您使用面向对象的编程语言时,没有理由再使用状态机”,如果您对执行速度有任何要求,则绝对不是这样。
- 作者的实施特别简短或简单,或者需要的维护少于增强型状态图数码相机,这取决于您的使用案例和个人品味,但不能用catagorically表示。 http://www.boost.org/doc/libs/1_55_0/libs/statechart/doc/tutorial.html#IntermediateTopicsADigitalCamera
请注意,切换状态需要分配!这将会扼杀速度。这可以通过将缓冲区中的所有状态分配在彼此旁边的缓冲区中来解决,以便节省一两个缓存未命中。但是,这需要对作者示例进行重大更改。
还要注意,未处理的事件不能像静态状态机那样内联和优化,因为状态模式它们位于动态间接层的后面。根据您的要求,这也是潜在的效率杀手。
从维护的角度来看,应该注意的是,记录未处理的事件不能从一个具有状态模式的中央超级事件中完成。此外,添加新的事件类型/处理函数需要向所有状态添加函数!我不认为维护友好。
我也更喜欢看表格中的所有过渡而不是查看每个州的内部运作。作者是正确的,添加一个状态更容易,但只是非常简单,例如使用提升状态图我只需要将状态添加到其父子状态列表中,这是唯一真正的区别。
我确实使用状态模式,在速度是非问题的情况下,状态机的层次结构很可能保持不变。作者是正确的,与状态机相比,状态模式通常更容易初始实现,并且通常更多的程序员应该使用更多的状态机。
状态模式的一个论点是它允许实现“开放闭合”状态机,其中状态机可以在库中定义然后由用户扩展,据我所知主流状态机是不可能的构架。
状态机可以以多种方式设计和实现。一种方法是使用Gang of Four书中描述的状态模式。但是还有其他模式来实现状态机。
例如,您可能希望通过阅读C / C ++第2版中的“实用UML状态图”一书来了解Miro Samek的研究。 (嵌入式系统的事件驱动编程)
您可能还会发现有趣的this question。
状态机只是工作中的状态模式,或者两者之间是否存在实际差异
TL; DR:想象一下,你需要用一个表现不同的状态来替换状态。然后想象你需要添加一个新状态。
完整答案。有一个很大的不同。
状态模式抽象状态并将它们彼此分离。因此,例如,您可以轻松地将一个特定状态替换为另一个特定状态。但是,当需要添加新的和/或新的转换时,您将不会乐于重写所有状态。
状态机抽象状态图本身并将其与转换有效负载分离。要更改特定状态,您必须修复整个图表。但是要添加状态或转换,您只需要修复图表。
如果有人仍然感兴趣,这是我的观点:
在状态机中,对象可以处于不同的状态,但我们并不关心它们在这些状态下的行为。实际上,我们只关心当对象转换到下一个状态时应用的操作。如果在Java中实现状态机,则状态将只是枚举或字符串,并且将有一个带有doAction()方法的Transition类。
另一方面,在状态模式中,您并不真正关心转换,而是关注对象在这些状态中的行为。转换只是一个实现细节,可以使您的状态行为相互分离。每个状态都是一个单独的类,具有自己的doAction()方法。
说状态模式使状态机过时是不正确的。如果每个状态的行为很重要,状态模式将是有用的,例如在游戏编程中,对象可以具有诸如“空闲”,“攻击”,“运行”之类的状态,并且在每个状态中您想要实现对象的行为。
但是对于订购在线产品这样的用例,您不关心订单对象的行为方式。您只关心订单处于“added_to_cart”状态,当发布“payment_finished”事件时,然后将其更改为“处理”状态。在这种情况下,state是Order类的简单枚举属性,因此使用状态机要好得多。
我发现状态模式有所不同。将它用于UI时更方便。我想说我想锁定状态。在状态模式上下文中,我可以创建一个布尔值并防止状态进一步改变。
这是一个Kotlin的例子:
inner class StateContext : State {
private var stateContext: State? = null
private var lockState: Boolean = false
fun isLockState(): Boolean {
return lockState
}
fun setLockState(lockState: Boolean): StateContext {
this.lockState = lockState//no further actions allowed. useful if you need to permenatley lock out the user from changing state.
return this
}
fun getState(): State? {
return this.stateContext
}
fun setState(state: State): StateContext {
if (!lockState) this.stateContext = state
return this
}
override fun doAction() {
this.stateContext?.doAction()
}
}
与状态机我不知道如何轻松完成。
我真的很喜欢状态机,我只担心状态(例如保存当前状态的枚举),而不是实际的实现细节(例如更改UI按钮颜色)。关于状态机的一件好事,就是你可以有一个记录状态变化的中心位置。我看到this library for kotlin by tinder看起来很有趣。但我个人认为你可以改变它们以做你想做的事情,只是更清洁一种方式与另一种方式。
什么是stateMachine呢? stateMachine更关心“什么是下一个州”,它强调了各州的转型,而不是其细节。它保持流动。通常您使用枚举创建它。这个article有助于清除它(下面的参考文献是从那里获取以帮助澄清差异)但实质上这将是一个状态机:
public enum LeaveRequestState {
Submitted {
@Override
public LeaveRequestState nextState() {
return Escalated;
}
@Override
public String responsiblePerson() {
return "Employee";
}
},
Escalated {
@Override
public LeaveRequestState nextState() {
return Approved;
}
@Override
public String responsiblePerson() {
return "Team Leader";
}
},
Approved {
@Override
public LeaveRequestState nextState() {
return this;
}
@Override
public String responsiblePerson() {
return "Department Manager";
}
};
public abstract LeaveRequestState nextState();
public abstract String responsiblePerson();
}
现在您知道每个事件的下一个过渡状态。所以状态机对于实际执行状态的转换非常重要:
LeaveRequestState state = LeaveRequestState.Submitted;
state = state.nextState();
assertEquals(LeaveRequestState.Escalated, state);
state = state.nextState();
assertEquals(LeaveRequestState.Approved, state);
state = state.nextState();
assertEquals(LeaveRequestState.Approved, state);
以上是关于状态机和状态模式的实现有什么区别?的主要内容,如果未能解决你的问题,请参考以下文章