簡體   English   中英

如何在java中將一個枚舉轉換為另一個枚舉?

[英]How to convert one enum to another enum in java?

我有;

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

並需要將其轉換為以下內容;

public enum Simple {
    DONE, RUNNING, ERROR;
}

所以首先PASSED - > DONEINPROCESS - > 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的代碼。 根據您的系統架構,這可能是也可能不是壞事。

使用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);
    }
    ...
}

特德的答案非常賈瓦利,但表達方式

passed == PASSED ? DONE : ERROR

也會做這個工作。

對我而言,這聽起來更像是概念問題,而不是編程問題。 為什么不直接刪除“簡單”枚舉類型並在程序的所有位置使用另一個?

只是為了讓另一個例子更清楚:你真的會嘗試為一周(星期一到星期五)的工作日和一周的所有日子(星期一到星期日)定義一個枚舉類型嗎?

這是帶有test的簡單枚舉映射器:

- 實施

- 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);
    }
}

}

- 測試

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));
}

}

Enums.getIfPresent()上的Guava的Enum.name()

我們的案例是這個案例的特殊專長。 我們有兩個Enum :一個是我們在應用程序中使用的,另一個是我們在核心庫中使用的。 核心庫由不同團隊的少數應用程序使用。 每個應用程序都查看整個功能的子集。 整個功能配置為枚舉,以打開和關閉,加油或關閉,選擇策略等。

所以我們最終得到:

  1. 庫的一個枚舉,包含所有可能的配置,從應用程序可見,也可以是一些特定於庫的
  2. 每個應用程序的一個枚舉,包含與應用程序在庫中可以看到/觸摸的內容相對應的文字,以及一些特定於應用程序的文字

然后,當我們將數據傳遞到庫時,我們會調整所有數據以及這些配置。 我們擁有所有枚舉,因此我們可以選擇在不同的枚舉中使用相同的文字調用相同的配置。

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;
}

當我們需要從一種類型轉換為另一種類型(app - > lib或lib - > app)時,我們以這種方式使用com.google.common.base.Enums中的getIfPresent()方法:

Aplication1Config config1App1 = FUNCTION_TWO;
LibraryConfig configLib = Enums.getIfPresent(LibraryConfig.class, config1App1.name()).orNull();

我們檢查configLib是否為null值,看看是否有成功的轉換。 我們使用的最后一步是APPX_FUNCTION_YYY,它們是特定於應用程序的, 並且用於方向lib - > app的轉換,而不是傳遞特定於庫的配置值(示例中為FUNCTION_FOUR )。

maven的依賴管理:

萬一有人需要它:

    <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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM