我有;
public enum Detailed {
PASSED, INPROCESS, ERROR1, ERROR2, ERROR3;
}
并且需要将其转换为以下内容:
public enum Simple {
DONE, RUNNING, ERROR;
}
首先,PASSED
→DONE
,INPROCESS
→RUNNING
,但所有错误都应为:ERROR
。 显然可以为所有值编写用例,但可能有更好的解决方案?
就我个人而言,我会创建一个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;
}
}
我发现这比Ted使用多态的方法更简单,因为我们不是真的在尝试提供不同的行为 - 只是一个不同的简单映射。
虽然你可能可以用序数值做一些聪明的事情,但它会更不明显,并且需要更多的代码 - 我认为没有任何好处。
一种方法是在您的 Detailed
枚举中定义一个名为 asSimple()
的方法:
public enum Detailed {
PASSED {
@Override
Simple asSimple() {
return DONE;
}
},
INPROCESS {
@Override
Simple asSimple() {
return RUNNING;
}
},
ERROR1,
ERROR2,
ERROR3;
public Simple asSimple() {
return Simple.ERROR; // default mapping
}
}
您可以在需要进行映射时简单地调用该方法:Detailed code = . . .
Simple simpleCode = code.asSimple();
这样做的优点是将与Detailed
枚举(可能应归属于该枚举)相关的映射知识放在一起。它的缺点是将Simple
的知识与Detailed
的代码混合在一起。这可能是好事,也可能不是,这取决于您的系统架构。
Detailed
需要了解Simple
的知识。 (基本上,我表达了您在评论中所表达的担忧,但是用了“劣势”的含糊批评。您的表述更加精确。)尽管如此,我认为这种方法值得考虑。 OP的枚举名称表明Detailed
在概念上是Simple
的细化。如果是这样的话,那么Detailed
与Simple
耦合并不是什么坏事(就像子类与父类耦合一样,这并不总是坏事)。 - Ted Hopp使用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);
}
...
}
Enums.getIfPresent()
关于Enum.name()
我们的情况是这种情况的一个特殊化。我们有两个Enum
:一个用于应用程序,另一个用于核心库。核心库被少数应用程序使用,由不同的团队使用。每个应用程序查看整个功能的子集。为了开关、调节和选择策略等,使用枚举配置整个功能。
因此,我们最终得到:
然后,当我们向库传递数据时,我们调整所有数据以及那些配置。我们拥有所有的枚举,所以我们可以选择在不同的枚举中使用相同的文字来调用相同的配置。
Enum LibraryConfig {
FUNCTION_ONE,
FUNCTION_TWO,
FUNCTION_THREE,
FUNCTION_FOUR;
}
Enum Aplication1Config {
FUNCTION_ONE,
FUNCTION_TWO,
FUNCTION_THREE,
APPL1_FUNCTION_ONE,
APPL1_FUNCTION_TWO;
}
Enum Aplication2Config {
FUNCTION_ONE,
FUNCTION_TWO,
FUNCTION_FOUR;
APPL2_FUNCTION_ONE;
}
当我们需要将一个类型转换为另一个类型时(从应用程序到库或从库到应用程序),我们使用com.google.common.base.Enums
中的getIfPresent()
方法,如下所示:
Original Answer翻译成"最初的回答"
Aplication1Config config1App1 = FUNCTION_TWO;
LibraryConfig configLib = Enums.getIfPresent(LibraryConfig.class, config1App1.name()).orNull();
configLib
是否为null
,以查看是否成功转换。我们使用这个最后一步是因为APPX_FUNCTION_YYY是应用特定的,并且用于在方向库- > 应用程序上进行转换,而不是传递配置值库特定(例如FUNCTION_FOUR
)。
以防万一有人需要:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
您可以使用Enum方法进行自己的转换,但需要注意异常以检测转换是否成功:
最初的回答
try {
Aplication1Config config1App1 = FUNCTION_TWO;
LibraryConfig configLib = LibraryConfig.valueOf(config1App1.name());
} catch (IllegalArgumentException iae) {
// if the conversion did not succeed
}
passed == PASSED ? DONE : ERROR
也可以完成工作。
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;
}
}
--映射器
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);
}
}
}
-- 测试
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));
}
}
enum
类型无法继承其他enum
类型,因此您几乎每次都需要进行这种类型的映射。 - Ted Hopp