2012-06-18 42 views
19

Tôi có;Làm thế nào để chuyển đổi một enum thành enum khác trong java?

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

và cần chuyển đổi nó thành nội dung sau;

public enum Simple { 
    DONE, RUNNING, ERROR; 
} 

Vì vậy, đầu tiên PASSED ->DONEINPROCESS ->RUNNING, nhưng những sai sót nên là: ERROR. Rõ ràng nó có thể viết các trường hợp cho tất cả các giá trị, nhưng có thể có một giải pháp tốt hơn?

Trả lời

19

Một cách là để xác định một phương pháp asSimple() trong Detailed enum của bạn:

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

Bạn có thể sau đó chỉ cần gọi phương thức khi bạn muốn làm việc lập bản đồ:

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

Nó có lợi thế của việc đưa kiến ​​thức về ánh xạ với các enum Detailed (có lẽ nó thuộc về). Có bất lợi khi có kiến ​​thức về Simple được trộn lẫn với mã cho Detailed. Điều này có thể hoặc có thể không phải là một điều xấu, tùy thuộc vào kiến ​​trúc hệ thống của bạn.

+2

Tôi nghĩ rằng đặt logic ánh xạ trong một enum vào một enum khác là phá vỡ đóng gói, giới thiệu khớp nối và giảm tính kết dính. Mối quan tâm của một enum chỉ đơn giản là đại diện cho một tập hợp các trạng thái (hoặc các khái niệm). Mối quan tâm của việc lập bản đồ từ một enum này đến enum khác nên được đóng gói riêng biệt. – Chomeh

+3

@Chomeh - Tôi đã lưu ý trong câu trả lời của tôi rằng 'Chi tiết' sẽ kết thúc đòi hỏi kiến ​​thức về' Đơn giản'. (Về cơ bản, tôi đã bày tỏ mối quan tâm tương tự như bạn đã làm trong bình luận của bạn, nhưng với sự phê bình khá mơ hồ gọi nó là một "bất lợi". Bạn đã chính xác hơn nhiều.) Tuy nhiên, tôi nghĩ rằng cách tiếp cận này là đáng xem xét. Tên enum của OP cho thấy 'Chi tiết' là khái niệm tinh lọc của' Simple'. Nếu đó là trường hợp, thì nó không phải là một điều tồi tệ ở tất cả những gì 'Chi tiết' được kết hợp với' Simple' (nhiều như nó không phải luôn luôn xấu mà một lớp con được kết hợp với lớp cha của nó). –

15

Cá nhân tôi chỉ cần tạo một Map<Detailed, Simple> và làm điều đó một cách rõ ràng - hoặc thậm chí sử dụng câu lệnh switch, có khả năng.

Một lựa chọn khác sẽ được vượt qua ánh xạ vào các nhà xây dựng - bạn chỉ có thể làm điều đó một cách tròn, tất nhiên:

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

(Tôi tìm thấy điều này đơn giản hơn cách tiếp cận của việc sử dụng đa hình của Ted, như chúng tôi tái không thực sự cố gắng để cung cấp khác nhau hành vi -. chỉ là một bản đồ đơn giản khác nhau)

trong khi bạn thể có khả năng làm điều gì đó xảo quyệt với giá trị thứ tự, nó sẽ ít nhiều rõ ràng, và lấy mã hơn - tôi don không nghĩ có là bất kỳ lợi ích nào.

+0

Phiếu bầu của tôi là cho bản đồ – Nu2Overflow

1

câu trả lời của Ted là rất Javaly, nhưng sự biểu hiện

passed == PASSED ? DONE : ERROR 

sẽ thực hiện công việc, quá.

+0

Điều gì đã xảy ra với phần INPROCESS -> RUNNING của bản đồ? –

+0

@Ted: tất nhiên bạn đã đúng, cảm ơn sự điều chỉnh. Tôi sẽ không đề xuất '' PASSED? XONG: INPROCESS? RUNNING: ERROR'' vì đó là, rõ ràng, ít có thể đọc được. (Sau đó, một lần nữa, tôi đã thấy rằng trước đây, và với định dạng tốt, nó [không nhìn quá lạ] (http://rors.org/2008/01/20/nested-ternary-operator) ...) – tiwo

0

Với tôi, âm thanh đó giống như vấn đề khái niệm hơn là vấn đề lập trình. Tại sao bạn không chỉ loại bỏ kiểu "enum" đơn giản và sử dụng cái khác thay vào đó ở tất cả các vị trí trong chương trình?

Chỉ cần làm rõ hơn với ví dụ khác: Bạn có thực sự cố gắng xác định loại enum cho ngày làm việc trong tuần (thứ Hai đến thứ Sáu) và enum khác cho tất cả các ngày trong tuần (thứ Hai đến Chủ Nhật) không?

+0

Vì Các kiểu 'enum' không thể kế thừa từ các kiểu' enum' khác trong Java, bạn bị mắc kẹt nhiều khi thực hiện ánh xạ kiểu này theo thời gian. –

6

Sử dụng EnumMap

tôi tách giao diện xml bên ngoài của tôi từ mô hình miền nội bộ của tôi bằng cách thực hiện một dịch vụ chuyển đổi. Điều này bao gồm ánh xạ enums từ jaxb tạo ra mã cho các mô hình miền enums.

Sử dụng EnumMap tĩnh gói gọn mối quan tâm của việc chuyển đổi trong lớp chịu trách nhiệm chuyển đổi.Nó gắn kết.

@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

Đây là mapper đơn giản enum với thử nghiệm:

- THI

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

} 

- THI

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

} 
Các vấn đề liên quan