これは、より一般化されたソリューションです。列挙型がコード値にマップされるときはいつでも使用します。たとえば、データベース テーブルにマップされる一連の離散値を列挙型で表す場合に特に役立ちます。定義されている次のいくつかの型は、一度だけ記述する必要があり、その後、任意の列挙型で使用できることに注意してください。
最初に、列挙型 (またはコレクションに格納される POJO) が実装するインターフェイスを定義します。
public interface Coded<T> {
T getCode();
}
以下はGoogle Guavaを活用していますが、 Optionalクラスを使用するのではなく、null チェックを実行できます。
public final class CodedFinder {
private CodedFinder() {}
public static <V, T extends Enum<T> & Coded<V>> T find(final Class<T> target, final V code) {
final Optional<T> found = findInternal(Arrays.asList(target.getEnumConstants()), code);
if (! found.isPresent()) {
throw new IllegalArgumentException(code.toString() + " is invalid for " + target.getSimpleName());
}
return found.get();
}
// Additional find methods for arrays and iterables redacted for clarity.
private static <V, T extends Coded<V>> Optional<T> findInternal(final Iterable<T> values, final V code) {
return Iterables.tryFind(values, CodedPredicate.of(code));
}
}
上記のメソッドは、Class#getEnumConstantsを使用して、列挙型で定義されたすべての値を取得します。呼び出される実際の find メソッドは、列挙型だけでなく、配列やコレクションなどにも使用できます。
Guava の find メソッドを利用するにはPredicateを定義する必要があります。
public final class CodedPredicate<V, T extends Coded<V>> implements com.google.common.base.Predicate<T> {
private final V value;
private CodedPredicate(final V value) {
this.value = value;
}
public static <V, T extends Coded<V>> CodedPredicate<V, T> of(final V value) {
return new CodedPredicate<V, T>(value);
}
public boolean apply(final T current) {
return value.equals(current.getCode());
}
}
その述語は汎用的であるため、実用的な実装Coded<Integer>
を持つその他の POJO を使用できますequals()
。
大量のコードのように見えますが、実際には上記で定義された 3 つの型のみがあり、これらは任意の数のプロジェクトで共有できます。値を検索するときはいつでも、簡単になります。
public final class GenderTest {
@Test(groups="unit")
public static void testValid() {
assert CodedFinder.find(Gender.class, "male") == Gender.m;
assert CodedFinder.find(Gender.class, "female") == Gender.f;
}
@Test(groups="unit", expectedExceptions=IllegalArgumentException.class)
public static void testInvalid() {
CodedFinder.find(Gender.class, "foo");
}
public enum Gender implements Coded<String> {
m("male"), f("female");
private final String value;
private Gender(final String option) {
value = option;
}
public String getCode()
{
return value;
}
}
}