如果在别处得到回答,请道歉;找不到足够的信息来说服自己最好的方法来做到这一点。我也意识到这是一个冗长的解释,没有代码,但请告诉我是否应该提供一些示例代码来帮助演示我正在做的事情。
基本上:
我使用状态模式的初衷是在从System.in解析这样的序列时简化代码(不要问语法,这是我必须使用的东西):
我通常为我希望收到的每种命令定义一个具体的状态。以上面的序列为例,我的状态集看起来像{WAITING_FOR_COMMAND,COMMAND_RECEIVED,PARSING_HEADER,PARSING_CONTENTS,PARSING_DONE,COMMAND_PROCESSED}。我最初是在WAITING_FOR_COMMAND,然后当收到“COMMAND NAME = X”时我会转换到COMMAND_RECEIVED,然后当“HEADER”进入时我会转换到PARSING_HEADER等。这个设计会遍历所有的边缘情况协议变得更容易,并且在协议被调整时也使代码易于更新/维护。显然比大规模切换语句和重复边界检查要好得多。
我遇到的问题是我发现自己在上下文类中声明了越来越多的状态变量,因为我充实了我的具体状态行为,并且知道这可能很糟糕,因为我创建了非常暴露的接口并且非常高上下文与具体状态类之间的联系。该协议中的命令序列可以任意长,我需要保存命令序列中每个项目赋予的信息,直到命令序列完成。
使用上面的命令序列作为示例,在“COMMAND ID = X”之后,我想在收到“ENDCOMMAND”后保存值X以备将来使用并完全处理命令。在“HEADER”之后,我希望保存标题信息,以便在我实际处理命令时收到“ENDCOMMAND”后将来使用。等等等等。简单地将commandId和头状态变量添加到上下文类现在可以工作,但看起来并不干净或完全封装在我身上。
有没有人对他们如何处理这个问题有任何高层建议?为此更好地使用状态设计模式吗?
请注意我一直在玩的一些想法:
非常感谢!对不起,这太详细了,如果我能说清楚的话,请告诉我。
答案 0 :(得分:1)
我使用了这种解析方式的枚举,每个州都有一个枚举。这方面就是一个例子 http://vanillajava.blogspot.co.uk/2011/06/java-secret-using-enum-as-state-machine.html
interface Context {
ByteBuffer buffer();
State state();
void state(State state);
}
interface State {
/**
* @return true to keep processing, false to read more data.
*/
boolean process(Context context);
}
enum States implements State {
XML {
public boolean process(Context context) {
if (context.buffer().remaining() < 16) return false;
// read header
if(headerComplete)
context.state(States.ROOT);
return true;
}
}, ROOT {
public boolean process(Context context) {
if (context.buffer().remaining() < 8) return false;
// read root tag
if(rootComplete)
context.state(States.IN_ROOT);
return true;
}
}
}
public void process(Context context) {
socket.read(context.buffer());
while(context.state().process(context));
}
答案 1 :(得分:0)
我首先考虑以下几点:
您的状态组件(WAITING_FOR_COMMAND,COMMAND_RECEIVED等)是否是应用程序逻辑的核心?也就是说,解析器处于什么状态以及它转换到什么状态,以确保应用程序正常工作真的很重要很多每个州将持有的价值是多少?这些值是否因州而异?如果你的答案是肯定的,那么你可能有一个状态模式的有效案例。但我经常看到状态机在某些地方使用它只是一种过度杀伤。
您的用例似乎更像需要Command模式和Interpreter模式(因为您似乎正在编写语法)。