改善状态机

时间:2017-05-27 22:58:07

标签: java switch-statement state-machine

所以我这个状态机(在下一个代码中有些状态因为它们还没有完成而丢失)有很多几乎相同的状态。 我确信必须有更好的方法来实现这一目标,但我找不到它(可能有课程,但我不确定)。

switch(firstState) {
    case INITIAL:
        if(c == 'g') {
            builder.append(c);
            firstState = FirstParserState.METHOD_G;
        }
        else if(c == 'p') {
            builder.append(c);
            firstState = FirstParserState.METHOD_P;
        }
        else
            firstState = FirstParserState.ERROR;

        break;
    case METHOD_G:
        if(c == 'e') {
            builder.append(c);
            firstState = FirstParserState.METHOD_E;
        }
        else
            firstState = FirstParserState.ERROR;

        break;
    case METHOD_E:
        if(c == 't') {
            builder.append(c);
            firstState = FirstParserState.METHOD_T;
        }
        else
            firstState = FirstParserState.ERROR;

        break;
    case METHOD_T:
        if(c == ' ') {
            method = builder.toString();
            builder.setLength(0);
            firstState = FirstParserState.WHISE_SPACE;
        }
        else
            firstState = FirstParserState.ERROR;

        break;
    case METHOD_P:
        if(c == 'o') {
            builder.append(c);
            firstState = FirstParserState.METHOD_O;
        }
        else
            firstState = FirstParserState.ERROR;

        break;
    case METHOD_O:
        if(c == 's') {
            builder.append(c);
            firstState = FirstParserState.METHOD_S;
        }
        else
            firstState = FirstParserState.ERROR;

        break;
    case METHOD_S:
        if(c == 't') {
            builder.append(c);
            firstState = FirstParserState.METHOD_T;
        }
        else
            firstState = FirstParserState.ERROR;

        break;
    case ERROR:
        ;//TODO: Dispatch error, malformed 1st line
        break;
}

我可以申请任何模式吗?还是什么?

提前致谢。

3 个答案:

答案 0 :(得分:0)

注意每个状态中的代码,用于测试输入字符,如果匹配,则接受输入并设置下一个状态:

if (c == ????) {
    builder.append(c);
    firstState = ????
}

您可以将此逻辑移动到某个方法中,并为每个状态/输入组合从switch中删除三行代码。

另外,请注意每个案例都有:

    else
        firstState = FirstParserState.ERROR;

您可以使用nextState变量从每个州消除这两行。在switch设置nextState = FirstParserState.ERROR之前。当输入匹配时,您可以在nextState中设置新状态,而不是直接在firstState中设置。 如果没有输入匹配,则各个州不需要执行任何特殊操作,因为nextState已经是FirstParserState.ERROR。然后在switch之后设置firstParserState = nextState以准备下一次迭代。

答案 1 :(得分:0)

您需要一个状态表,它将当前状态和当前输入字符映射到下一个状态。然后你所要做的就是打开下一个状态并采取适当的行动。

答案 2 :(得分:0)

我认为你应该摆脱开关盒部分。您可以在不为每个州创建类的情况下实现状态机设计模式,如果您有许多状态,还有一个更优雅的解决方案:基于枚举的状态机

Enum类实现ParserStateListener.java接口,其中包含可以更改对象的方法'状态。

public enum FirstParserState implements ParserStateListener{

INITIAL{
    public void onEventChange(char c, StringBuilder builder, FirstParserState nextState) {
        if (c == 'g') {
            builder.append(c);
            nextState = FirstParserState.METHOD_G;
        } else if (c == 'p') {
            builder.append(c);
            nextState = FirstParserState.METHOD_P;
        } else
            nextState = FirstParserState.ERROR;

    }
},METHOD_G{
    public void onEventChange(char c, StringBuilder builder, FirstParserState nextState) {
        if (c == 'e') {
            builder.append(c);
            nextState = FirstParserState.METHOD_E;
        } else
            nextState = FirstParserState.ERROR;

    }
},METHOD_E{
    public void onEventChange(char c, StringBuilder builder, FirstParserState nextState) {
        if (c == 't') {
            builder.append(c);
            nextState = FirstParserState.METHOD_T;
        } else
            nextState = FirstParserState.ERROR;

    }
},ERROR{
    public void onEventChange(char c, StringBuilder sb, FirstParserState nextState) {
        // TODO Auto-generated method stub

    }
};

}

这是监听器类,用于保持将改变对象状态的操作。

public interface ParserStateListener {

public void onEventChange(char c, StringBuilder sb, FirstParserState nextState);

}

然后你就可以写下你的客户代码:

 public void doOperations(){
    StringBuilder sb = new StringBuilder();

    FirstParserState firstParserState = FirstParserState.INITIAL;
    firstParserState.onEventChange(c, sb, firstParserState);        

}

这种方法只是第一眼我不知道你的具体要求。如果您需要多次调用onEventChange(c, sb, firstParserState)方法,并且已经知道了转换路径,则可以将路径放到集合中,然后通过调用此方法进行迭代。