Java 读/写二进制结构:如何简化此代码?

Java 读/写二进制结构:如何简化此代码?,java,coding-style,binary-data,Java,Coding Style,Binary Data,我正在编写一个网络应用程序,它发送和接收大量不同类型的二进制数据包,我正在尝试尽可能容易地向我的应用程序添加新类型的数据包 现在,我创建了一个包类,并为每种不同的包创建了它的子类。然而,它并不像看上去那么干净;我最终得到了如下代码: static class ItemDesc extends Packet { public final int item_id; public final int desc_type; public final String filename

我正在编写一个网络应用程序,它发送和接收大量不同类型的二进制数据包,我正在尝试尽可能容易地向我的应用程序添加新类型的数据包

现在,我创建了一个
类,并为每种不同的包创建了它的子类。然而,它并不像看上去那么干净;我最终得到了如下代码:

static class ItemDesc extends Packet {
    public final int item_id;
    public final int desc_type;
    public final String filename;
    public final String buf;

    public ItemDesc(Type t, int item_id, int desc_type, String filename, String buf) {
        super(t); // sets type for use in packet header
        this.item_id = item_id;
        this.desc_type = desc_type;
        this.filename = filename;
        this.buf = buf;
    }

    public ItemDesc(InputStream i) throws IOException {
        super(i); // reads packet header and sets this.input
        item_id = input.readInt();
        desc_type = input.readByte();
        filename = input.readStringWithLength();
        buf = input.readStringWithLength();
    }

    public void writeTo(OutputStream o) throws IOException {
        MyOutputStream dataOutput = new MyOutputStream();
        dataOutput.writeInt(item_id);
        dataOutput.writeByte(desc_type);
        dataOutput.writeStringWithLength(filename);
        dataOutput.writeStringWithLength(buf);
        super.write(dataOutput.toByteArray(), o);
    }
}
ItemDesc = [('item_id', 'int'), ('desc_type', 'byte'), ...]
这种方法让我烦恼的是代码重复——我重复了四次数据包结构。我很乐意避免这种情况,但我找不到一个合理的方法来简化它

如果我是用Python编写的,我会创建一个包含所有可能字段类型的字典,然后定义新的数据包类型,如下所示:

static class ItemDesc extends Packet {
    public final int item_id;
    public final int desc_type;
    public final String filename;
    public final String buf;

    public ItemDesc(Type t, int item_id, int desc_type, String filename, String buf) {
        super(t); // sets type for use in packet header
        this.item_id = item_id;
        this.desc_type = desc_type;
        this.filename = filename;
        this.buf = buf;
    }

    public ItemDesc(InputStream i) throws IOException {
        super(i); // reads packet header and sets this.input
        item_id = input.readInt();
        desc_type = input.readByte();
        filename = input.readStringWithLength();
        buf = input.readStringWithLength();
    }

    public void writeTo(OutputStream o) throws IOException {
        MyOutputStream dataOutput = new MyOutputStream();
        dataOutput.writeInt(item_id);
        dataOutput.writeByte(desc_type);
        dataOutput.writeStringWithLength(filename);
        dataOutput.writeStringWithLength(buf);
        super.write(dataOutput.toByteArray(), o);
    }
}
ItemDesc = [('item_id', 'int'), ('desc_type', 'byte'), ...]
我想我可以在任何函数式语言中做类似的事情。然而,我看不到将这种方法应用于Java的方法

(也许我太迂腐了,或者我已经习惯了函数式编程和编写代码,这样我就可以避免任何重复:)


提前感谢您的建议。

我觉得没问题。您可能只想在继承链上抽象数据包的一些“通用”部分,因此不需要读取它们,但像您这样重复格式是有意义的,因为您有从构造函数中读取原始数据、从流中读取数据和写入数据的理由。我看它没什么问题。

我觉得没问题。您可能只想在继承链上抽象数据包的一些“通用”部分,因此不需要读取它们,但像您这样重复格式是有意义的,因为您有从构造函数中读取原始数据、从流中读取数据和写入数据的理由。我看不出有什么问题。

我同意@silky的观点,即您当前的代码是一个很好的解决方案。在我看来,一点重复的(尽管不是重复的)代码并不是一件坏事

如果您想要一个更像python的解决方案,您可以:

  • 用某种保序映射结构替换ItemDesc的成员属性,使用在映射上迭代的公共
    writeTo
    方法进行序列化。您还需要为每个属性添加getter,并替换现有字段的所有用法
  • 用属性对象替换成员属性,并使用属性序列化而不是二进制写入
  • 编写一个通用的
    writeTo
    方法,该方法使用Java反射来访问成员属性及其类型并序列化它们

  • 但在所有3种情况下,代码都会比当前的“丑陋”代码更慢、更复杂、更脆弱。我不会这么做。

    我同意@silky的观点,即您当前的代码是一个很好的解决方案。在我看来,一点重复的(尽管不是重复的)代码并不是一件坏事

    如果您想要一个更像python的解决方案,您可以:

  • 用某种保序映射结构替换ItemDesc的成员属性,使用在映射上迭代的公共
    writeTo
    方法进行序列化。您还需要为每个属性添加getter,并替换现有字段的所有用法
  • 用属性对象替换成员属性,并使用属性序列化而不是二进制写入
  • 编写一个通用的
    writeTo
    方法,该方法使用Java反射来访问成员属性及其类型并序列化它们

  • 但在所有3种情况下,代码都会比当前的“丑陋”代码更慢、更复杂、更脆弱。我不会这么做。

    我不确定您是否可以在java中这样做,但也许您可以重用其中一个CTOR:

    public ItemDesc(InputStream i) throws IOException {
        super(i); // reads packet header and sets this.input
    
        this(input.readInt(), input.readByte(), input.readStringWithLength(), input.readStringWithLength());
    }
    

    WARE“this”表示调用这个类的ctor,不管语法是什么。

    我不确定您是否可以在java中这样做,但是您可以重用其中一个ctor:

    public ItemDesc(InputStream i) throws IOException {
        super(i); // reads packet header and sets this.input
    
        this(input.readInt(), input.readByte(), input.readStringWithLength(), input.readStringWithLength());
    }
    

    “this”表示调用这个类,不管语法是什么。

    看起来很不错。我怀疑你能减少代码,它看起来很不错。我怀疑你能减少代码。这不能解决问题-我仍然需要重复数据包结构来编写数据包。这不能解决问题-我仍然需要重复数据包结构来编写数据包。