改进状态机

Improving 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;
}

有没有我可以应用的模式?或者什么?

提前致谢。

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

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

您可以将此逻辑移动到一个方法中,并从 switch 中为每个 state/input 组合删除三行代码。

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

    else
        firstState = FirstParserState.ERROR;

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

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

我认为你应该去掉 switch case 部分。您可以在不为每个状态创建 class 的情况下实现状态机设计模式,如果您有多个状态,还有一个更优雅的解决方案:基于枚举的状态机

Enum class 实现 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

    }
};

}

这是侦听器 class 以保持将更改对象状态的操作'

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) 方法,并且你已经知道你的转换路径,你可以将你的路由放入一个集合中,然后通过调用这个方法来迭代。