美文网首页微服务架构和实践netty系列程序员
深入netty之五责任链模式在decode和encode中的应用

深入netty之五责任链模式在decode和encode中的应用

作者: 小七赛文 | 来源:发表于2018-04-28 14:50 被阅读11次

    前面我们讲了对如下的数据协议使用“模板方法模式”来解析包头和包尾的过程:

    数据协议1数据协议1

    现在接着来说一说对包体的解析。
    这里拿出三个数据包来作为例子:

    1. 初始化命令
      这个命令的包体如下:

      初始化命令初始化命令

      这个命令包体很简单,只有一个字节,表明是“初始化命令”。

    2. 查版本号命令
      这个命令的包体如下:

      查版本号命令查版本号命令

      这个命令包体相对复杂一点,一共3个字节。

    3. 读钱箱电子ID命令
      这个命令的包体如下:

      读钱箱电子ID命令读钱箱电子ID命令

      这个命令有4个字节。

    从上述包体格式可以看出,包体开头都有一个字节来标识命令类型,然后才是命令体内容。
    对于这样的包体格式,特别适合使用“责任链模式”,下面来详细说一说如何使用该模式做encode。
    首先是父类的实现:

    public class CashboxBodyEncoder {
    
    private CashboxBodyEncoder next;
    
    public CashboxBodyEncoder(CashboxBodyEncoder next) {
        this.next = next;
    }
    

    责任链上的每一个节点,都必须初始化下一个节点,如上述代码中 next所示。

        public void doEncoder(CashboxBaseData baseData, ByteBuf out)
        {
            if (this.next != null) this.next.doEncoder(baseData, out);
        }
    }
    

    doEncoder方法是做encode工作的方法,它来判断当前节点有没有下一个节点,如果有,则把工作给下一个节点做。
    以上就是“责任链模式”的父类。
    下面来看看子类实现。
    首先是“初始化”命令:

    @Slf4j
    public class CashboxInitialiseEncoder extends CashboxBodyEncoder{
        public CashboxInitialiseEncoder(CashboxBodyEncoder next) {
            super(next);
        }
    

    前面说了,每一个子类在初始化的时候,都需要指定下一个节点对象。

    @Override
    public void doEncoder(CashboxBaseData baseData, ByteBuf out) {
    

    覆盖父类的doEncoder方法。

        if (baseData.getType() == INITIALISE)
        {
            log.info("进入初始化命令写入...");
        }
    

    首先判断,如果是“初始化”命令,则做encode。这里“初始化”命令的命令类型,已经在encode包头的时候顺手做了,所以,在做“初始化”命令的encode的时候,没有任何事情可以做。

            else super.doEncoder(baseData, out);
        }
    }
    

    如果不是“初始化”命令,则交给父类的doEncoder方法处理,而它的处理是将数据交给下一个节点处理,这就是责任顺着责任链往下传的意图。
    下面,我们来看查看版本号命令的实现:

    @Slf4j
    public class CashboxVersionReadResultDecoder extends CashboxBodyDecoder{
    
        public CashboxVersionReadResultDecoder(CashboxBodyDecoder next) {
            super(next);
        }
    
        @Override
        public CashboxBaseData decode(CashboxBaseData baseData, ByteBuf buffer, CashboxParamHandleType handleType) {
            if (baseData.getType() == CASHBOX_VERSION)
            {
                log.info("解析固件版本号结果...");
                CashboxVersionReadResultData data = new CashboxVersionReadResultData((CashboxBaseResultData) baseData);
                data.setVersion(buffer.getCharSequence(RESULT_PORT_BEGIN, data.getLength() - SIZE_OF_DATA_4_CODE, Charset.forName("utf-8")).toString());
                return data;
            }
            else return super.decode(baseData, buffer, handleType);
        }
    }
    

    读电子钱箱ID命令的代码就不再给出了,感兴趣的话,大家可以自己尝试写写。
    最后是实例化各命令类的代码:

    public class CashboxBodyDecoderFactory {
    public static CashboxBodyDecoder getBodyDecoder()
    {
        return new CashboxResult4AckDecoder(
                    new CashboxResult4NakDecoder(
                            new CashboxSelfcheckDataDecoder(
                                    new CashboxParaDataDecoder(
                                            new CashoutResultDataDecoder(
                                                    new CashboxParamResultDataDecoder(
                                                            new CashboxCoreStateResultDecoder(
                                                                    new CashboxVersionReadResultDecoder(
                                                                            new CashboxInitialiseResultDecoder(
                                                                                    new CashboxStateResultDataDecoder(null))))))))));
        }
    }
    

    可以看到,除了最后一个节点,每一个节点都有下一个节点,到了最后一个节点,责任的传递才会中止。
    其类图如下所示:

    类图类图

    相关文章

      网友评论

        本文标题:深入netty之五责任链模式在decode和encode中的应用

        本文链接:https://www.haomeiwen.com/subject/ftuglftx.html