使用状态模式设计在Java中实现通信协议

2024-04-25

如果在其他地方回答了这个问题,我们深表歉意;找不到足够的信息来说服自己最好的方法来做到这一点。我还意识到这是一个冗长的解释,没有代码,但是让我知道我是否应该编写一些示例代码来帮助演示我正在做的事情。

基本上:

  • 使用 System.in/out 在 Java 中实现通信协议
  • 当前的方法是实现一种状态模式,其中 Scanner 在上下文类中的 System.in 上实例化
  • 具体状态调用上下文方法从扫描器读取,然后根据扫描器返回的值适当地执行操作/转换状态

我使用状态模式的最初目的是在从 System.in 解析这样的序列时简化代码(不要问语法,这是我必须处理的内容):

  • 命令名称=X
  • HEADER
  • 标题信息行
  • 内容
  • 命令内容行
  • 结束内容
  • 结束命令

我通常为我期望收到的每种类型的命令定义一个具体状态。以上面的序列为例,我会有一个看起来像 {WAITING_FOR_COMMAND, COMMAND_RECEIVED, PARSING_HEADER, PARSING_CONTENTS, PARSING_DONE, COMMAND_PROCESSED} 的状态集。我最初处于 WAITING_FOR_COMMAND 状态,然后当收到“COMMAND NAME=X”时,我会转换到 COMMAND_RECEIVED,然后当“HEADER”进入时,我会转换到 PARSING_HEADER 等。这种设计使得遍历所有边缘情况协议更容易,并且在协议调整时也使代码易于更新/维护。显然比大量的 switch 语句和重复的边界检查要好得多。

我遇到的问题是,当我充实具体的状态行为时,我发现自己在上下文类中声明了越来越多的状态变量,并且知道这可能很糟糕,因为我正在创建非常暴露的接口以及在上下文和具体状态类。该协议中的命令序列可以是任意长,我需要保存命令序列中每个项目传递的信息,直到命令序列完整。

以上面的命令序列为例,在“COMMAND ID=X”之后,我想保存值X以供将来在收到“ENDCOMMAND”并完全处理该命令后使用。在“HEADER”之后,我想保存标头信息以供将来在收到“ENDCOMMAND”后实际处理命令时使用。等等等等。现在,只需将 commandId 和标头状态变量添加到上下文类即可,但对我来说似乎根本不干净或封装得不好。

有人对如何解决这个问题有任何高层次的建议吗?对此是否有更好的状态设计模式使用?

只是要注意我一直在玩的一些想法:

  • 为每种类型的命令序列定义状态上下文,并在从 System.in 接收到相关命令时调用适当的上下文;这看起来几乎和巨大的开关块一样混乱,并且似乎使设计过于复杂
  • 设计一个支持复合 FSM 的成熟 FSM 架构,其中每个命令序列在总体 FSM 中占据自己的 FSM;这对我来说似乎太过分了
  • 为每个命令序列类型创建具有各种子类的 ProtocolCommand 对象;我可以在转换时将它们传递到每个状态,并逐渐构建它们......但这会使状态界面变得混乱,并迫使所有状态摄取它们不一定会使用的参数

非常感谢!抱歉,这太冗长了,如果我可以澄清任何事情,请告诉我。


我使用了一个枚举来进行这种解析方式,每个状态都有一个枚举。一个例子在这里http://vanillajava.blogspot.co.uk/2011/06/java-secret-using-enum-as-state-machine.html 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));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用状态模式设计在Java中实现通信协议 的相关文章

随机推荐