2012-06-18 36 views
19

私は持っています。Javaで列挙型を別の列挙型に変換するにはどうすればよいですか?

public enum Detailed { 
    PASSED, INPROCESS, ERROR1, ERROR2, ERROR3; 
} 

とする必要があります。

public enum Simple { 
    DONE, RUNNING, ERROR; 
} 

だから、最初PASSED - >DONEINPROCESS - >RUNNINGが、すべてのエラーは次のようになりますERROR。明らかに、すべての値に対してケースを書くことは可能ですが、より良い解決策があるかもしれません。

Detailed code = . . . 
Simple simpleCode = code.asSimple(); 

それは利点があります:あなたはマッピングを行いたいとき

public enum Detailed { 
    PASSED { 
     @Override 
     Simple asSimple() { 
      return PASSED; 
     } 
    }, 
    INPROCESS { 
     @Override 
     Simple asSimple() { 
      return RUNNING; 
     } 
    }, 
    ERROR1, 
    ERROR2, 
    ERROR3; 
    public Simple asSimple() { 
     return Simple.ERROR; // default mapping 
    } 
} 

あなたは、単にメソッドを呼び出すことができます。

答えて

19

一つの方法は、あなたのDetailed列挙方法asSimple()を定義することですDetailed enum(おそらくそれが属している)でマッピングの知識を伝えることです。 DetailedのコードにSimpleの知識が混在するという欠点があります。これは、システムアーキテクチャによっては、悪いことかもしれません。

+2

私は別の列挙に列挙内のマッピング・ロジックを置くことは、カプセル化を壊すのカップリングを導入し、凝集性を軽減していることと思います。列挙型の懸念は、単純に一連の状態(または概念)を表すことにすぎないはずです。ある列挙型から別の列挙型へのマッピングの懸念は、別々にカプセル化する必要があります。 – Chomeh

+3

@Chomeh - 私は 'Detailed'は' Simple'の知識を必要と終わるだろうと私の答えに注記をしました。 (基本的に、私はあなたがあなたのコメントで行った同じ懸念を表明しましたが、「不利益」それを呼び出すのではなく漠然とした批判で。あなたがはるかに正確だった。)それにもかかわらず、私はこのアプローチは検討する価値があると思います。 OPの列挙名は、「詳細」が概念的には「単純」の改良であることを示唆しています。その場合は、それは 'Detailed'が(それはサブクラスは親クラスに結合されていることを常に悪くはない限り)Simple''に結合されていることは全く悪いことではありません。マップの一部を実行している> - –

15

私は個人的にはMap<Detailed, Simple>を作成し、それを明示的に行うか、可能であればswitch文を使用します。

別の方法としては、コンストラクタにマッピングを渡すことであろう - あなたは片道ラウンドそれをのみ行うことができ、もちろん:

public enum Detailed { 
    PASSED(Simple.DONE), 
    INPROCESS(Simple.RUNNING), 
    ERROR1(Simple.ERROR), 
    ERROR2(Simple.ERROR), 
    ERROR3(Simple.ERROR); 

    private final Simple simple; 

    private Detailed(Simple simple) { 
     this.simple = simple; 
    } 

    public Simple toSimple() { 
     return simple; 
    } 
} 

我々は「として(私は、多型を使用してのテッドのアプローチよりも、この単純見つけます。ちょうど別の単純なマッピング)

あなた潜在的に順序値を持つ狡猾な何かを行うことができますが、それははるかに少ない明らかであり、より多くのコードを取る - - Iドン本当に異なる行動を提供しようとしていない再それはないと思う何か利益があります。

+0

私の投票はインプロセスに何が起こったマップ – Nu2Overflow

1

テッドの答えは非常にJavalyですが、表現

passed == PASSED ? DONE : ERROR 

も、仕事をするだろう。

+0

のためにあるのですか? –

+0

@テッド:もちろん、あなたは正しいです、訂正のおかげで。私は ''合格?完了:インプロセス? RUNNING:ERROR''と表示されます。 (その後、再び、私が前にいることを見てきた、との良好なフォーマットで、それは(http://rors.org/2008/01/20/nested-ternary-operator)[あまりにも奇妙に見えるしません] ...) – tiwo

0

私にとっては、プログラミングの問題よりも概念的な問題のように聞こえます。単純な列挙型を削除して、代わりにプログラム内のすべての場所で他の列挙型を使うのはなぜですか?

もう1つの例を使用すると、より明確になります。週の作業日(月曜日から金曜日)と週のすべての日(月曜日から日曜日)の別の列挙型を実際に定義しようとしますか?

+0

ので、 'enum'型はJavaの他の' enum'型から継承することはできません。あなたはこの種のマッピングをしばしばやっています。 –

6

使用EnumMap

私は、変換サービスを実装することで、私の内部ドメインモデルから私の外部のXMLインターフェイスを切り離します。これには、jaxb生成コードの列挙型をドメインモデルの列挙型にマッピングすることも含まれます。

静的EnumMapを使用すると、変換を行うクラス内の変換の問題がカプセル化されます。その粘着性のある。ここで

@Service 
public class XmlTransformer { 

    private static final Map<demo.xml.Sense, Constraint.Sense> xmlSenseToSense; 
    static { 
     xmlSenseToSense = new EnumMap<demo.xml.Sense, Constraint.Sense> (
      demo.xml.Sense.class); 
     xmlSenseToSense.put(demo.xml.planningInterval.Sense.EQUALS, 
      Constraint.Sense.EQUALS); 
     xmlSenseToSense.put(demo.xml.planningInterval.Sense.GREATER_THAN_OR_EQUALS, 
      Constraint.Sense.GREATER_THAN_OR_EQUALS); 
     xmlSenseToSense.put(demo.xml.planningInterval.Sense.LESS_THAN_OR_EQUALS, 
      Constraint.Sense.LESS_THAN_OR_EQUALS); 
    } 
    ... 
} 
0

はテストと簡単な列挙型マッパーです:

- 実装

- ENUMS

public enum FirstEnum { 

A(0), B(1); 

private final int value; 

private FirstEnum(int value) { 
    this.value = value; 
} 

public int getValue() { 
    return value; 
} 
} 

public enum SecondEnum { 

C(0), D(1); 

private final int valueId; 

private SecondEnum(int valueId) { 
    this.valueId = valueId; 
} 

public int getValueId() { 
    return valueId; 
} 

} 

--MAPPER

import java.lang.reflect.InvocationTargetException; 
import java.util.HashMap; 
import java.util.Map; 

import org.apache.commons.beanutils.PropertyUtils; 
import org.apache.commons.lang3.Validate; 

import com.google.common.collect.Sets; 

public class EnumPropertyMapping { 

private final Map<?, ?> firstMap; 
private final Map<?, ?> secondMap; 

private final Class<?> firstType; 
private final Class<?> secondType; 

private EnumPropertyMapping(
     Map<?, ?> firstMap, Map<?, ?> secondMap, Class<?> firstType, Class<?> secondType) { 

    this.firstMap = firstMap; 
    this.secondMap = secondMap; 
    this.firstType = firstType; 
    this.secondType = secondType; 
} 

public static Builder builder() { 
    return new Builder(); 
} 

@SuppressWarnings("unchecked") 
public <R> R getCorrespondingEnum(Object mappedEnum) { 
    Validate.notNull(mappedEnum, "Enum must not be NULL"); 
    Validate.isInstanceOf(Enum.class, mappedEnum, "Parameter must be an Enum"); 

    if (firstType.equals(mappedEnum.getClass())) { 
     return (R) firstMap.get(mappedEnum); 
    } 

    if (secondType.equals(mappedEnum.getClass())) { 
     return (R) secondMap.get(mappedEnum); 
    } 

    throw new IllegalArgumentException("Didn't found mapping for enum value: " + mappedEnum); 
} 

public static class Builder { 

    private final Map<Object, Object> firstEnumMap = new HashMap<>(); 
    private final Map<Object, Object> secondEnumMap = new HashMap<>(); 
    private Class<?> firstEnumType; 
    private Class<?> secondEnumType; 

    public <T extends Enum<T>> Builder addFirst(Class<T> enumType, String propertyName) { 
     firstEnumType = enumType; 
     initMap(firstEnumMap, enumType.getEnumConstants(), propertyName); 
     return this; 
    } 

    public <T extends Enum<T>> Builder addSecond(Class<T> enumType, String propertyName) { 
     secondEnumType = enumType; 
     initMap(secondEnumMap, enumType.getEnumConstants(), propertyName); 
     return this; 
    } 

    private void initMap(Map<Object, Object> enumMap, Object[] enumConstants, String propertyName) { 
     try { 
      for (Object constant : enumConstants) { 
       enumMap.put(PropertyUtils.getProperty(constant, propertyName), constant); 
      } 
     } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) { 
      throw new IllegalStateException(ex); 
     } 
    } 

    public EnumPropertyMapping mapEnums() { 
     Validate.isTrue(firstEnumMap.size() == secondEnumMap.size()); 
     Validate.isTrue(Sets.difference(firstEnumMap.keySet(), secondEnumMap.keySet()).isEmpty()); 

     Map<Object, Object> mapA = new HashMap<>(); 
     Map<Object, Object> mapB = new HashMap<>(); 

     for (Map.Entry<Object, Object> obj : firstEnumMap.entrySet()) { 
      Object secondMapVal = secondEnumMap.get(obj.getKey()); 
      mapA.put(obj.getValue(), secondMapVal); 
      mapB.put(secondMapVal, obj.getValue()); 
     } 
     return new EnumPropertyMapping(mapA, mapB, firstEnumType, secondEnumType); 
    } 
} 

} 

- TEST

import org.junit.Test; 

import com.bondarenko.common.utils.lang.enums.FirstEnum; 
import com.bondarenko.common.utils.lang.enums.SecondEnum; 

import static junit.framework.TestCase.assertEquals; 

public class EnumPropertyMappingTest { 

@Test 
public void testGetMappedEnum() { 
    EnumPropertyMapping mapping = EnumPropertyMapping.builder() 
                            .addSecond(SecondEnum.class, "valueId") 
                            .addFirst(FirstEnum.class, "value") 
                            .mapEnums(); 

    assertEquals(SecondEnum.D, mapping.getCorrespondingEnum(FirstEnum.B)); 
    assertEquals(FirstEnum.A, mapping.getCorrespondingEnum(SecondEnum.C)); 
} 

} 
関連する問題