7

値がさまざまな属性を持つJava列挙型を作成しました。これらの属性は、次のいずれかの方法で保存できます。

フィールドの使用:

enum Eenum {
  V1(p1),
  V2(p2);

  private final A attr;

  public A attr() { return attr; }

  private Eenum(A attr) {
    this.attr = attr;
  }
}

抽象メソッドの使用:

enum Eenum {
  V1 {
    public A attr() { return p1; }
  },

  V2 {
    public A attr() { return p2; }
  }

  public abstract A attr();
}

クラスレベルマップの使用:

enum Eenum {
  V1,
  V2;

  public A attr() { return attrs.get(this); }

  private static final Map<Eenum, A> attrs;

  static {
    ImmutableMap.Builder<Eenum, A> builder = ImmutableMap.builder();
    builder.put(V1, p1);
    builder.put(V2, p2);
    attrs = builder.build();
  }
}

どちらを優先するかをどのように決定すればよいですか?

ありがとう!

4

3 に答える 3

3

私はあなたが最も簡単だと思うものをやります。

一般的に、データを使用して実装できるコードは記述しません。私は最初のものを使用します。

私の実際のユースケースには、すべての列挙値に関連しないいくつかの属性があります

属性ごとに意味がある場合は、これらのアプローチを組み合わせて使用​​できます。

4番目のオプションは、抽象メソッドを持たないことです。

enum Eenum {
  V1 {
    public A attr() { return p1; }
  },

  V2 {
    public A attr() { return p2; }
  }, 
  V3, V4, V5, V6;

  public A attr() { return defaultA; }
}
于 2012-11-01T18:49:38.507 に答える
0

(自分の質問に答えて、試してみて学んだことを共有できるようにしています。)

特定のケースの決定を下すために尋ねるべき質問は次のとおりです。

1:属性値には前方参照が含まれていますか?

場合V1によっては、の属性への参照が必要になることがあり、V2その逆もあります。これはまれなケースではありません。あなたがそのようなものを扱っているならenum、アプローチ1は単にうまくいかないでしょう。コンパイラは(当然のことながら)不正な前方参照について文句を言います。他の2つのアプローチのいずれかを使用できます。

ここで、属性値の計算にコストがかかり、定数である場合は、1回だけ計算する必要があります。アプローチ2では、列挙値ごとにローカル変数を導入し、そこに結果をキャッシュする必要があります。これは冗長ですが、パフォーマンスが向上します。アプローチ3では、結果はとにかく1回だけ計算されるため、余分な作業を行う必要はありません。これは、アプローチ2よりも読みやすくなりますが、パフォーマンスは多少低下します。ケースで保証されている特定のトレードオフに従って、これらの間の設計を行ってください。

2:結果をキャッシュする必要がありますか?

前の箇条書きの2番目の段落を参照してください。

前方参照がない場合は、アプローチ1も使用できます。ただし、属性の計算に関連する計算が複雑な場合は、他の2つのアプローチのいずれかを使用することをお勧めします。

3:属性はすべての列挙値に関連していますか?

そうでない場合は、非常に論理的に、Mapここを使用する必要があります。つまり、アプローチ3です。

4:いくつかの列挙値のいくつかの属性のデフォルト値はありますか?

その場合、3つのアプローチすべてを使用でき、それらはすべて異なるトレードオフのセットを提供します。

アプローチ1の場合:属性をデフォルト値に初期化する補助コンストラクターを定義します。そのような属性が複数ある場合、これは実行可能なアプローチではない可能性があります。

アプローチ2の場合:これは実際には、PeterLawreyが上記で提案した「4番目の」アプローチのようになります。enum本体にデフォルト値を返すメソッドがあります。また、一部の列挙値は、このメソッドをオーバーライドして別の値を返します。これもまた、かなり冗長です。

アプローチ3の場合:効率が低下します。他のすべての点で良い。

于 2012-11-04T00:00:56.860 に答える
0

それらのどれも。これを行う:

interface HasAttr<T> {
    T attr();
}

enum Eenum implements HasAttr<A> {

    // use "fields" version - ideally with constructor version

    public A attr() {
        return field;
    }

}

このパターンは、次のようなメソッドを可能にする基本的な抽象型デザインパターンに従います。

public void someMethod(HasAttr<A> hasAttr);  // pass anything that is HasAttr<a>

固定タイプよりも:

public void someMethod(Eenum eenum); // locked into passing an Eenum

また、そして重要なことに、特に列挙型が実際の接続などを使用している場合は、テストのためにモックを作成する方が簡単です。

私はあなたに許可します、これはすべて、列挙型が「重要」である場合にのみ適用されます。それが単なる古い列挙型である場合、私はそれが単なるコード膨張であることに同意します(これも嫌いです)

于 2012-11-01T18:51:08.697 に答える