1

さまざまな種類のバイナリ パケットを送受信するネットワーク アプリを作成しています。新しい種類のパケットをアプリにできるだけ簡単に追加できるようにしようとしています。

ここでは、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);
    }
}

このアプローチで気になるのは、コードの繰り返しです。パケット構造を 4 回繰り返しています。これを避けたいのですが、単純化する合理的な方法がわかりません。

Python で書いていたら、考えられるすべてのフィールド タイプのディクショナリを作成し、次のように新しいパケット タイプを定義します。

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

どの関数型言語でも同様のことができると思います。ただし、このアプローチを Java に適用する方法がわかりません。

(多分、私はあまりにも衒学的であるか、関数型プログラミングとコードを書くコードを書くことに慣れていたので、繰り返しを避けることができました:))

ご提案いただきありがとうございます。

4

3 に答える 3

1

あなたの現在のコードが良い解決策であるという@silkyに同意します。少し反復的な (ただし重複していない) コードは悪いことではありません、IMO.

より Python に似たソリューションが必要な場合は、次のことができます。

  1. ItemDesc のメンバー属性をある種の順序を維持するマップ構造に置き換え、マップwriteToを反復処理する一般的な方法を使用してシリアル化を行います。また、各属性にゲッターを追加し、既存のフィールドのすべての使用を置き換える必要があります。
  2. メンバー属性を Properties オブジェクトに置き換え、バイナリ書き込みの代わりに Properties シリアル化を使用します。
  3. writeToJava リフレクションを使用してメンバー属性とその型にアクセスし、それらをシリアル化する共通メソッドを記述します。

しかし、3 つのケースすべてにおいて、コードは現在の「醜い」コードよりも遅く、複雑になり、壊れやすくなる可能性があります。私はこれをしません。

于 2009-09-04T00:47:12.223 に答える
0

私には大丈夫に見えます。継承チェーンのパケットの「一般的な」部分の一部を抽象化して、それらを読み取る必要がないようにしたいだけかもしれませんが、フォーマットを繰り返しているのは理にかなっています。コンストラクターからの生の読み取り、ストリームからの読み取り、および書き込みの場合。私はそれに問題はないと思います。

于 2009-09-03T23:54:58.780 に答える
0

Javaでこれを実行できるかどうかはわかりませんが、ctorの1つを再利用できるかもしれません:

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

    this(input.readInt(), input.readByte(), input.readStringWithLength(), input.readStringWithLength());
}

「これ」は、構文が何であれ、このクラス ctor への呼び出しを意味します。

于 2009-10-31T21:35:26.263 に答える