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

时间:2009-09-03 23:52:09

标签: java coding-style binary-data

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

现在,我创建了一个Packet类,并为每种不同类型的数据包创建了它的子类。然而,它并不像看起来那么干净;我最终得到了这样的代码:

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

这种方法困扰我的是代码重复 - 我重复了四次数据包结构。我很乐意避免这种情况,但我看不出合理的方法来简化它。

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

ItemDesc = [('item_id', 'int'), ('desc_type', 'byte'), ...]

我想我可以用任何功能语言做类似的事情。但是,我看不到将这种方法用于Java的方法。

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

提前感谢您提出任何建议。

3 个答案:

答案 0 :(得分:1)

我同意@silky您当前的代码是一个很好的解决方案。一些重复(但不重复)的代码并不是坏事,IMO。

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

  1. 使用某种保留顺序的地图结构替换ItemDesc的成员属性,使用遍历地图的常见writeTo方法进行序列化。您还需要为每个属性添加getter,并替换现有字段的所有用法。
  2. 使用Properties对象替换成员属性,并使用“属性序列化”而不是“二进制写入”。
  3. 编写一个公共writeTo方法,该方法使用Java反射来访问成员属性及其类型并对其进行序列化。
  4. 但在所有3种情况下,代码将比当前“丑陋”代码更慢,更复杂并且可能更脆弱。我不会这样做。

答案 1 :(得分:0)

好像我。您可能只想在继承链上抽象数据包的某些“常规”部分,因此您不需要读取它们,但重复这种格式是有道理的,因为您有一个从构造函数中读取raw,从流中读取和写入的情况。我认为没有错。

答案 2 :(得分:0)

我不确定你能在java中做到这一点 - 但也许你可以重用一个ctors:

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'意味着对这个类ctor的调用,无论语法是什么。