我想知道一个状态机是否只是状态模式的功能,还是这两者之间实际存在差异?
我找到了一篇题为“状态设计模式与状态机”的文章,但说到底,他仅表示状态模式使状态机过时,但并没有描述状态机与状态模式的实现有什么具体区别。
我想知道一个状态机是否只是状态模式的功能,还是这两者之间实际存在差异?
我找到了一篇题为“状态设计模式与状态机”的文章,但说到底,他仅表示状态模式使状态机过时,但并没有描述状态机与状态模式的实现有什么具体区别。
请注意,切换状态需要分配!这将导致速度变慢。这可以通过在一个缓冲区中将所有状态放置在一起来进行修复,以节省缓存丢失或两个。但是,这将需要对作者示例进行重大更改。
还要注意,未处理的事件无法像静态状态机中那样内联和优化掉,因为在状态模式中它们在动态间接层后面。这也可能会根据您的要求导致效率低下。
从维护的角度来看,需要注意的是使用状态模式无法从一个中央超级状态记录未处理的事件。此外,添加新的事件类型/处理程序函数需要向所有状态添加一个函数!我认为这不太容易维护。我更喜欢在表格中看到所有转换,而不是查看每个状态的内部工作。作者正确地指出添加状态更容易,但只有非常微小的差异,例如使用boost statecharts,我只需将状态添加到其父级子状态列表中,这才是真正的区别。我在速度不是问题且状态机层次结构很可能保持平坦的情况下使用状态模式。作者正确地指出,与状态机相比,状态模式的初始实现通常更容易,并且通常应该有更多的程序员使用状态机。状态模式的一个论点是它允许实现“开放封闭”状态机,其中可以在库中定义状态机,然后由用户进行扩展,这在我所知道的主流状态机框架中是不可能的。如果还有人感兴趣,这是我的看法:
在状态机中,对象可以处于不同的状态,但我们并不真正关心这些状态下它们如何行为。事实上,我们只关心当对象转换到下一个状态时应用了什么操作。如果你在Java中实现一个状态机,则状态将仅是一个枚举或字符串,并且将有一个Transition类,其中包含doAction()方法。
另一方面,在状态模式中,您并不真正关心转换,而是关心对象在这些状态下如何行为。转换只是一种实现细节,可以使状态行为相互解耦。每个状态将是一个单独的类,具有自己的doAction()方法。
说状态模式使状态机过时是不正确的。如果每个状态的行为很重要,例如在游戏编程中,对象可以拥有“空闲”,“攻击”,“奔跑”等状态,并且在每个状态中,您希望实现对象的行为,则状态模式将非常有用。
但对于像在线订购产品这样的用例,您并不关心订单对象如何行为。您只关心订单是否处于“已添加到购物车”状态,当发布“付款完成”事件时,然后将其更改为“正在处理”状态。在这种情况下,状态是订单类的简单枚举属性,因此使用状态机更好。
状态机可以用多种方式进行设计和实现。一种方法是使用《设计模式》中所描述的状态模式。但是还有其他模式可以实现状态机。
例如,您可以查看Miro Samek的研究,并阅读他的书籍《Practical UML statecharts in C/C++, 2nd ed. (Event-Driven Programming for Embedded Systems)》。
您还可能会发现这个问题很有趣。
我注意到状态模式有所不同。在使用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 按钮颜色),我确实很喜欢状态机。状态机好的一点是你可以有一个中央位置来记录状态变化。我看到了 Tinder 开发的 Kotlin 库,链接在这里,它看起来非常有趣。但我个人认为,你可以将它们全部更改成你想要的方式,只是一种更干净的方式而已。
那么什么是状态机呢?状态机更关心“下一个状态” ,强调状态转换而不是状态的细节。它维护流程。通常使用枚举来创建状态机。这篇文章帮助清楚地阐述了这个概念(下面的参考文献也取自该文章),但本质上这就是一个状态机:
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);