设计模式问题涉及N个状态和它们之间的转换

时间:2010-01-13 15:22:28

标签: java design-patterns automata state-machine

我手头有问题而且我没有使用哪种设计模式。 问题是这样的:

我必须构建一个具有'N'状态的系统,并且我的系统必须根据某些条件从任何状态转换到任何其他状态。 例如: 在条件1,从状态1移动到3,在状态1从状态1移动到4。

即使是从一个州到另一个州的过渡也可以在两个或更多不同的条件下完成。

例如,在以下情况下可以完成从状态1到状态3的转换:
条件1:“它是一个星期天”
条件2:“它的下雨”
条件3:“下雨和星期天”
在每种情况下,状态3的处理可能不同。

我希望我能够清楚地理解这个问题。请帮助。

非常感谢

6 个答案:

答案 0 :(得分:35)

它显然是有限状态机的情况,但它更好地结合条件而不是为每个组合创建新条件。我不喜欢维基百科上的状态模式的Java示例,因为状态知道在很多场景中没有意义的其他状态。跟踪状态,适用的条件状态的转换表有助于解决该问题。

对于面向对象的有限状态机我的两分钱。你可以在OO方面做一些改进,但它可以解决这个问题。

class Transition {
    State from;
    Set<Condition> conditions;
    State to;
}

class State {
    String state;
}

class Condition {
    String condition;
}

状态机可以用上述类型构造。没有错误检查,但如果在某些条件下找不到下一个状态,则可能抛出异常或其他内容。

class StateMachine {
    List<Transition> transitions;
    State current;

    StateMachine(State start, List<Transition> transitions) {
        this.current = start;
        this.transitions = transitions;
    }

    void apply(Set<Condition> conditions) {
        current = getNextState(conditions);
    }

    State getNextState(Set<Condition> conditions) {
        for(Transition transition : transitions) {
            boolean currentStateMatches = transition.from.equals(current);
            boolean conditionsMatch = transition.conditions.equals(conditions);
            if(currentStateMatches && conditionsMatch) {
                return transition.to;
            }
        }
        return null;
    }
}

试运行:

修改:根据您的评论添加更多转场和新状态:

State one = new State("one");
State two = new State("two");
State three = new State("three");

Condition sunday = new Condition("Sunday");
Condition raining = new Condition("Raining");
Condition notSunday = new Condition("Not Sunday");
Condition notRaining = new Condition("Not Raining");

List<Transition> transitions = new ArrayList<Transition>();
transitions.add(one, new Set(sunday), three);
transitions.add(one, new Set(sunday), two); // <<--- Invalid, cant go to two and three
transitions.add(one, new Set(raining), three);
transitions.add(one, new Set(sunday, raining), three);
transitions.add(one, new Set(notSunday, notRaining), three);

StateMachine machine = new StateMachine(one, transitions);
System.out.print(machine.current); // "one"
machine.apply(new Set(sunday, raining));
System.out.print(machine.current); // "three

我在使用状态机进行相当大的项目时遇到了一些痛苦的经历。问题在于复合状态。就像你提到的复合条件(星期日和下雨)一样,技术上可能是复合状态,可以进一步细分为单位状态。在您的情况下可能会或可能不是这种情况,但仍值得一提。如果是这种情况,最好修改经典有限状态机并使用状态集而不是单个状态来表示from和to状态。如果您的N很大,这将有助于保持理智水平不变。想想hotmail文件夹和gmail标签。转换表将显示为

Transition(Set<State> from, Set<Condition> conditions, Set<State> to)

答案 1 :(得分:13)

这听起来像是finite state machine

的典型用法

简而言之,状态机描述了系统可以处于的各种状态,以及它可以在哪些条件下从一个状态到另一个状态。状态机完全按照您的英文描述进行描述。它可以使用state diagrams

正式描述

在代码中你可以制作这样的状态机:

 enum State { Init, ShowMenu, ShowMsg, DisplayVideo, Exit };
 State state = State.Init;

 while (state != State.Exit)
 {
      switch(state)
      {
           case State.Init:
                init();
                state = State.ShowMenu;
                break;
           case State.ShowMenu:
                if(lastMenuItemSelected==1) state = State.ShowMsg;
                if(lastMenuItemSelected==2) state = State.DisplayVideo;
                break;
           case State.ShowMsg:
                ....
                break;
           ....
 }

我不确定我是否对Java有正确的语法...我更喜欢C#

答案 2 :(得分:9)

state pattern不会开展工作吗?

答案 3 :(得分:1)

我注意到你的例子的第一件事是State 3 =(State 1 == true&amp;&amp; State 2 == true)。随着更多可能的状态的参与,这将无法很好地扩展。如果您只考虑是下雨还是星期天,您可以进行这样的枚举,有4种可能的类型:

enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }

这将允许您在需要编码时在开关块中干净地陈述条件。但是如果你还要考虑外面是否温暖,你必须再添加4个值来捕获所有可能的条件。在您的项目中,您的代码可能需要捕获比您当前设想的更多条件。

至于设计模式,状态模式及其Java example on Wikipedia看起来是个好地方。

维基百科的示例有一个StateContext类,其中有一个名为setState的方法,它采用名称。我想过建议您在此处添加状态确定逻辑,但这会使您的StateContext类需要过于接近其他类的实现细节。最好在一个类中设置一个确定系统状态的方法,这个方法很容易知道从一个状态到另一个状态的条件。这样,如果您的项目将来需要更改,并且您有更多状态要跟踪或不同的条件,您只需要在一个地方维护逻辑。

答案 4 :(得分:1)

正如其他人所说,状态机可以用程序代码用开关建模,也可以用状态模式的OO代码建模,这可能就是你所追求的。

然而,第三种方法是将其实际编码为图形,其中状态为节点,条件为有向边。然后可以使用访客模式将图表应用于不同的用途。这将特别适用于状态和/或转换可以由用户定义的设计,但可能比其他答案中描述的硬编码状态机更加占用内存。

答案 5 :(得分:1)

国家设计模式适用于国家变革的概念。整个过程生命周期可以分为多个阶段。每个阶段的完成过程从一个状态退出并进入另一个状态。

例如,在JSF框架中,整个Web请求响应生命周期分为六个阶段:

每个阶段完成后,从一个状态退出并进入另一个状态。例如,在RestoreValuePhase之后,我们可以将ViewRestored称为退出状态,将RequestApply称为进入状态。

因此,要实现状态设计模式需要以这样的方式划分整个过程:它可以在多个阶段中处理,每个阶段出口定义状态变化。

现在让我们通过以下代码了解这一点。

任何项目生命周期都可以分为多个阶段,如

requirementAssessment
Design
Development
QualityAssessment
Deploy
Closure

所以这些是以下示例中使用的阶段

规则:

  1. 我们需要定义一个可以存储进程当前状态的类。下面代码中的NextPhase类正在这样做。

  2. 我们需要定义一个接口,其中我们可以提供将在每个阶段实现的联系方法。在下面的代码中ProjectPhase正在这样做。

  3. 在此处详细了解州设计模式 - State Design Pattern

    http://efectivejava.blogspot.in/2013/09/java-state-design-patten-oops-state.html?utm_source=BP_recent