2012-01-10 8 views
5

Java enumを扱う際のコード再利用に最適なデザインパターンに関する質問があります。基本的に、私が達成しようとしているのは、静的なビジネスコレクション(定数のセット)をモデル化するいくつかの列挙型を定義できることですが、最小限のコーディングでそれらの間で振る舞いを共有したいと思います。Java Enumを拡張する

これは、抽象クラスからのクラス継承で実現するのは簡単ですが、Javaの列挙型は拡張できないため(インターフェイスのみを実装できます)、このタイプの作業は面倒でエラーが発生しやすいコピー/列挙型から列挙型へのコード)。すべての列挙型の間で共有されるべき "ビジネスロジック"の例には、文字列の変換、インスタンスと論理比較などが含まれます。

私のベストショットは、ビジネスインタフェースと組み合わせてヘルパークラスを使用しています。これまではコードの複雑さを軽減することができました(すべての列挙体は依然としてヘルパークラスを宣言して呼び出す必要があります)。 (ただ明確にする)の例を参照してください:

public enum MyEnum { 
    A, B, C; 

    // Just about any method fits the description - equals() is a mere example 
    public boolean equals(MyEnum that) { 
     ObjectUtils.equals(this, that); 
    } 
} 

どうStackOverflowersは、この「言語機能」を扱うのですか?

+0

と 'Delegate' @、私は決してきたんロンボクを試みることができます列挙型で試しました。 –

+0

Java 6では、列挙型は最終クラスです。それらを拡張することはできません。私はJava 7は同じだと信じています。 – DwB

+1

そのための列挙型は作成されていません。クラス(または列挙型のクラス)を使用するか、ロジックを分離するかどちらかです。このような場合にファクトリパターンを使用することができます(動作がenumからenumまで十分に異なる場合)。 – Viruzzo

答えて

2

私は同じことをするか、Enumをスーパーエニュームに組み合わせます。

Java 8ではこれがより簡単になります。インターフェイスメソッドに対してdefault実装を定義し、enumにインターフェイスを拡張することができます。

+0

'enum'をスーパーの' 'enum'に組み合わせることはどういう意味ですか?たとえそれが意味をなさないとしても、値AとBを比較できるので、それは安全ではないでしょうか? – lsoliveira

+0

安全でない可能性があります。むしろコンテキストに依存します。 –

+0

最後に、他のすべてのソリューションはDRYの原則に違反することなく複雑さを増すので、これが解決策であるようです。私の指を渡すと、いつか拡張クラスがJavaになります。 – lsoliveira

2

有限状態を表すこと以外は、動作が必要ない場合を除き、ほとんど役に立ちません。enumsです。

enumsの動作を必要とするリファクタリングをclassesFactoryとすることをお勧めします。

+0

enumは定数を使って値を渡すよりもずっと安全であり、操作に多くの利便性を与えます(EnumSet <...>、 'switch'など)。私は彼らがC#の相手よりもはるかに強力ではないことに同意しますが、彼らはまだ自分の場所を持っています(特に、あなたはいくつかのコードをリファクタリングしているだけで、完全なリライトはできません)。 – lsoliveira

+0

私は 'enums'が古い' final static int CONSTANT = 1'よりも優れていることに同意し、構文的砂糖はいいですが、私が 'enum'に振る舞うたびに後悔しました。 –

+0

@Isoliveira Wait ** LESS ** intの周りに基本的に構文的な砂糖であるC#enumsより強力ですか?あなたはどうやってその結論に達しましたか?とにかく私はある程度Garettに同意します:列挙型は有限状態を表現するためにそこにあります。その場合、私はなぜそれらを拡張する必要があるのか​​分かりません。しかし、列挙型で単純な(!)状態を持つことは、しばしば有用です。それが些細な方法以上の場合、それはクラスでなければなりません。しかし、例えば。私の本では 'getComplement()'メソッドがうまくいくでしょう。 – Voo

3

再利用可能なロジックを専用(非enum)クラスに移動してから、その列にenumを委任することができます。ここに例があります:

[参考:PlusTwo extends PlusOneの継承は推奨されません(b/c PlusTwoはPlusOneではありません)。それはここだけで、既存のロジックを拡張することができるという点を説明します。]

public interface Logic { 
    public int calc(int n); 
} 

public static class PlusOne implements Logic { 
    public int calc(int n) { return n + 1; } 
} 

public static class PlusTwo extends PlusOne { 
    @Override 
    public int calc(int n) { return super.calc(n) + 1; } 
} 

public static enum X { 
    X1, X2; 
    public Logic logic; 

    public int doSomething() { 
    return logic.calc(10); 
    } 
} 

public static enum Y { 
    Y1, Y2; 
    public Logic logic; 

    public String doSomethingElse() { 
    return "Your result is '" + logic.calc(10) + "'"; 
    } 
} 

public static void main(String[] args) { 
    // One time setup of your logic: 
    X.X1.logic = new PlusOne(); 
    X.X2.logic = new PlusTwo(); 
    Y.Y1.logic = new PlusOne(); 
    Y.Y2.logic = new PlusTwo(); 

    System.out.println(X.X1.doSomething()); 
    System.out.println(X.X2.doSomething()); 
    System.out.println(Y.Y1.doSomethingElse()); 
    System.out.println(Y.Y2.doSomethingElse()); 
} 
+0

最後に、これは私の最初の提案の単なる変形です。実装ロジックを切り離すだけです。私はまた 'Logic'のための工場を使いたいと思います。私のようにそれを公開してはいけません。 – lsoliveira

0

これは少し醜い見えるかもしれませんが、一般的にあなたに必要な機能を提供することができます。

あなたはインターフェイス

public interface MyEnumInterface<T extends Enum<T>> { 

    String getBusinessName(); 

    T getEnum(); 

} 

実装

public enum OneOfMyEnums implements MyEnumInterface<OneOfMyEnums>{ 

    X, Y, Z; 

    @Override 
    public String getBusinessName() { 
     return "[OneOfMyEnums]" + name(); 
    } 

    @Override 
    public OneOfMyEnums getEnum() { 
     return this; 
    } 

} 

そしてユーティリティクラスの代わりに、あなたの親クラスを持つことができます

public class MyEnumUtils { 

    public static <T extends Enum<T>> String doSomething(MyEnumInterface<T> e){ 
     e.getBusinessName(); // can use MyEnumInterface methods 
     e.getEnum().name(); // can use Enum methods as well 
     return null; 
    } 

} 
+0

このアプローチは興味深いですが、クライアントを 'enum'の代わりにユーティリティクラスに依存させることで契約を逆転させます(' equals() 'メソッドは' MyEnumUtils'に入ります)。 – lsoliveira

関連する問題