状态机和状态模式的实现有什么区别?

时间:2013-11-08 12:49:59

标签: design-patterns architecture state state-machine

我想知道状态机是否只是工作中的状态模式,或者这两者之间是否存在差异?

我发现了这个article with the bold title "the state design pattern vs state machine"但是在一天结束时他只说状态模式使状态机过时但后来没有描述什么与状态模式的实现相比,它是状态机

6 个答案:

答案 0 :(得分:17)

我向同事描述这种差异的方式是状态模式是许多独立封装状态的更分散的实现,而状态机更加单一。状态机的单一性质意味着单个状态将难以在不同的机器中重用,并且将状态机分解为多个编译单元更加困难。另一方面,这种单片设计允许更好地优化状态机,并允许许多实现在表中的一个位置表示所有转换信息。这尤其适用于负责状态机体系结构或功能的人员不熟悉其实现的编程语言的情况。请记住,许多工程和数学专业的学生都学过状态机,但很少或根本没有接受过教育。编程领域。与状态模式的页面和页面相比,向这些类型的人呈现转换,动作和警卫表要容易得多。

虽然这篇文章实际上是一篇很好的读物,但我在几点上不同意作者:

请注意,切换状态需要分配!这将会扼杀速度。这可以通过将缓冲区中的所有状态分配在彼此旁边的缓冲区中来解决,以便节省一两个缓存未命中。但是,这需要对作者示例进行重大更改。

另请注意,未处理的事件无法像静态状态机那样内联和优化,因为状态模式它们位于动态间接层的后面。根据您的要求,这也是潜在的效率杀手。

从维护的角度来看,应该注意的是,记录未处理的事件不能通过状态模式从一个中央超级事件中完成。此外,添加新的事件类型/处理函数需要向所有状态添加函数!我不认为维护友好。

我也更喜欢在表中查看所有转换,而不是查看每个州的内部工作。作者是正确的,添加一个状态更容易,但只是非常简单,例如使用提升状态图我只需要将状态添加到其父子状态列表中,这是唯一真正的区别。

我确实在速度是非问题的情况下使用状态模式,并且状态机的层次结构很可能保持不变。作者是正确的,与状态机相比,状态模式通常更容易初始实现,并且通常更多的程序员应该使用更多的状态机。

状态模式的一个参数是它允许实现“打开关闭”状态机,其中状态机可以在库中定义然后由用户扩展,这是我不知道的主流的状态机框架。

答案 1 :(得分:9)

状态机可以通过多种方式设计和实现。一种方法是使用Gang of Four书中描述的状态模式。但是还有其他模式来实现状态机。

例如,您可能希望通过阅读C / C ++第二版中的 Practical UML statecharts一书来了解Miro Samek的研究。 (嵌入式系统的事件驱动编程)

您可能还会发现有趣的this question

答案 2 :(得分:1)

  

状态机只是工作中的状态模式,或者两者之间是否存在差异

TL; DR:想象一下,您需要使用行为不同的状态替换状态。然后想象你需要添加一个新状态。

完整答案。存在很大差异。

状态模式抽象状态并将它们彼此分离。因此,例如,您可以轻松地将一个特定状态替换为另一个特定状态。但是,当需要添加新的状态和/或新的转换时,您将无法重写所有状态。

状态机抽象状态图本身并将其与转换有效负载分离。要更改特定状态,您必须修复整个图表。但是要添加状态或转换,您只需要修复图表。

答案 3 :(得分:1)

如果有人仍然感兴趣,这是我的观点:

在状态机中,对象可以处于不同的状态,但我们并不关心在这些状态下的行为。实际上,我们只关心当对象转换到下一个状态时应用的操作。如果在Java中实现状态机,状态将只是一个枚举或一个字符串,并且将有一个带有doAction()方法的Transition类。

另一方面,在状态模式中,您并不真正关心转换,而是关注对象在这些状态中的行为。转换只是一个实现细节,可以使您的状态行为相互分离。每个州都是一个单独的类,拥有自己的doAction()方法。

说状态模式使状态机过时是不正确的。如果每个状态的行为很重要,状态模式将是有用的,例如在游戏编程中,对象可以具有诸如“空闲”,“攻击”,“运行”之类的状态,并且在每个状态中您想要实现对象的行为

但是对于订购在线产品的用例,您不关心订单对象的行为方式。您只关心订单处于“added_to_cart”状态,当发布“payment_finished”事件时,然后将其更改为“处理”状态。在这种情况下,state是Order类的简单枚举属性,因此使用状态机要好得多。

答案 4 :(得分:1)

我写了一篇有关状态设计模式和状态机的文章:https://medium.com/@1gravityllc/the-super-state-design-pattern-166127ce7c9a。在文章中,我展示了它们的重点不同,但是它们也不是互斥的。有一种方法可以将两者结合起来以提供超级状态设计模式

状态设计模式的重点是封装行为以创建可重用,可维护的组件(状态)。

有限状态机的重点是状态及其转换(由状态图捕获),而不是实际行为(这是实现细节)。

本文介绍了如何通过使用有限状态机来描述和管理对象的状态及其转换,以使用状态设计模式将行为委托给状态对象,从而将这两个概念结合起来。

答案 5 :(得分:0)

我发现状态模式有所不同。将它用于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);