2

バイナリ ファイル形式のパーサーを作成しています。私が読んでいる逆シリアル化された構造を表すクラスを作成しました。そこでは、最終変数を使用して抽出されたデータを保持したいと考えています。

class MyObject {
    final int my_x;
    final int my_y;
    final int my_z;
}

私が遭遇している問題は、特定のフィールドの存在が設定されている特定のフラグに依存することです。例えば:

MyObject(InputStream is) {
    my_x = in.read();
    if (my_x == 1) {
        my_y = in.read();
        if (my_y == 1) {
            my_z = in.read();
        }
    }
}

ただし、my_ymy_zが初期化されていない可能性があるため、これによりエラーが発生します。これらの条件は 5 ~ 6 レベルの深さにすることができ、ブランチ ツリーの各レベルでどのフィールドが読み取られないかを追跡したくありません。もう 1 つの問題は、特定のフラグに基づいて、トップレベルの構造と同じパターンで処理したいサブオブジェクトが存在する可能性があることです。

class MyObject {
    final int my_x;
    final SubObject my_subobject;

    MyObject(InputStream is) {
        my_x = is.read();
        if (my_x == 1)
            my_subobject = new SubObject(is);
    }

    class SubObject {
        final int sub_x;
        final int sub_y;

        SubObject(InputStream is) {
            sub_x = is.read();
            if (sub_x == 1)
                sub_y = is.read();
        }
    }
}

考えられるフラグの各組み合わせを処理するためにコードをひねらずに、フィールドを final にする方法はありますか?

4

1 に答える 1

4

ローカル変数を使用してfinal、コンストラクターの最後でフィールドに割り当てます。

public MyObject(InputStream is) {
    int x = default_x_value;
    int y = default_y_value;
    int z = default_z_value;
    x = in.read();
    if (x == 1) {
        y = in.read();
        if (y == 1) {
            z = in.read();
        }
    }
    my_x = x;
    my_y = y;
    my_z = z;
}

あるいは (Jon Skeet がコメントで示唆しているように)、デフォルトのないコンストラクターの適切な値を計算する静的ファクトリ メソッドを使用します。

public static MyObject makeMyObject(InputStream is) {
    int x = default_x_value;
    int y = default_y_value;
    int z = default_z_value;
    x = in.read();
    if (x == 1) {
        y = in.read();
        if (y == 1) {
            z = in.read();
        }
    }
    return new MyObject(x, y, z);
}

3 番目のアプローチは、初期化オブジェクト クラスを定義することです。

public class MyObject {
    private static class MyObjectInitializer {
        int x = default_x_value;
        int y = default_y_value;
        int z = default_z_value;
        MyObjectInitializer(InputStream is) {
            x = in.read();
            if (x == 1) {
                y = in.read();
                if (y == 1) {
                    z = in.read();
                }
            }
        }
    }
    public MyObject(InputStream is) {
        this(new MyObjectInitializer(is));
    }
    private MyObject(MyObjectInitializer init) {
        my_x = init.x;
        my_y = init.y;
        my_z = init.z;
    }
}

初期化クラスは、それ自体でユーティリティを持っている場合があります。その場合、それ (および対応するMyObjectコンストラクター) をパブリックにすることができます。

于 2013-05-08T17:48:44.033 に答える