문제

이 인터페이스를 구현하는 수많은 Enum이 있습니다.

/**
 * Interface for an enumeration, each element of which can be uniquely identified by it's code
 */
public interface CodableEnum {

    /**
     * Get the element with a particular code
     * @param code
     * @return
     */
    public CodableEnum getByCode(String code);

    /**
     * Get the code that identifies an element of the enum
     * @return
     */
    public String getCode();
}

전형적인 예는 다음과 같습니다.

public enum IMType implements CodableEnum {

    MSN_MESSENGER("msn_messenger"),
    GOOGLE_TALK("google_talk"),
    SKYPE("skype"),
    YAHOO_MESSENGER("yahoo_messenger");

    private final String code;

    IMType (String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }   

    public IMType getByCode(String code) {
        for (IMType e : IMType.values()) {
            if (e.getCode().equalsIgnoreCase(code)) {
                return e;
            }
        }
    }
}

상상할 수 있듯이 이러한 메서드는 CodableEnum의 모든 구현에서 사실상 동일합니다.이 중복을 제거하고 싶지만 솔직히 방법을 모르겠습니다.다음과 같은 클래스를 사용해 보았습니다.

public abstract class DefaultCodableEnum implements CodableEnum {

    private final String code;

    DefaultCodableEnum(String code) {
        this.code = code;
    }

    public String getCode() {
        return this.code;
    }   

    public abstract CodableEnum getByCode(String code);  
}

그러나 이는 다음과 같은 이유로 상당히 쓸모가 없는 것으로 판명되었습니다.

  1. 열거형은 클래스를 확장할 수 없습니다.
  2. 열거형 요소(SKYPE, GOOGLE_TALK 등)는 클래스를 확장할 수 없습니다.
  3. DefaultCodableEnum 자체가 Enum이 아니기 때문에 getByCode()의 기본 구현을 제공할 수 없습니다.java.lang.Enum을 확장하기 위해 DefaultCodableEnum을 변경하려고 시도했지만 이는 허용되지 않는 것 같습니다.

성찰에 의존하지 않는 제안이 있습니까?고마워요, 돈

도움이 되었습니까?

해결책

중복된 코드를 CodeableEnumHelper 수업:

public class CodeableEnumHelper {
    public static CodeableEnum getByCode(String code, CodeableEnum[] values) {
        for (CodeableEnum e : values) {
            if (e.getCode().equalsIgnoreCase(code)) {
                return e;
            }
        }
        return null;
    }
}

CodeableEnum 클래스는 여전히 getByCode 방법이지만, 방법의 실제 구현은 적어도 한 곳에 집중되어 있습니다.

public enum IMType implements CodeableEnum {
    ...
    public IMType getByCode(String code) {
        return (IMType)CodeableEnumHelper.getByCode(code, this.values());
    } 
}

다른 팁

추상 열거형은 잠재적으로 매우 유용합니다(현재는 허용되지 않습니다).그러나 Sun의 누군가에게 이를 추가하도록 로비하려는 경우 제안과 프로토타입이 존재합니다.

http://freddy33.blogspot.com/2007/11/abstract-enum-ricky-carlson-way.html

썬 RFE:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570766

dave의 코드를 정리하려면:

public class CodeableEnumHelper {
    public static <E extends CodeableEnum> E getByCode(
        String code, E[] values
    ) {
        for (E e : values) {
            if (e.getCode().equalsIgnoreCase(code)) {
                return e;
            }
        }
        return null;
    }
}

public enum IMType implements CodableEnum {
    ...
    public IMType getByCode(String code) {
        return CodeableEnumHelper.getByCode(code, values());
    } 
}

또는 더 효율적으로:

public class CodeableEnumHelper {
    public static <E extends CodeableEnum> Map<String,E> mapByCode(
        E[] values
    ) {
        Map<String,E> map = new HashMap<String,E>();
        for (E e : values) {
            map.put(e.getCode().toLowerCase(Locale.ROOT), value) {
        }
        return map;
    }
}

public enum IMType implements CodableEnum {
    ...
    private static final Map<String,IMType> byCode =
        CodeableEnumHelper.mapByCode(values());
    public IMType getByCode(String code) {
        return byCode.get(code.toLowerCase(Locale.ROOT));
    } 
}

제가 작성한 현지화 구성 요소와 비슷한 문제가 있었습니다.내 구성 요소는 어려운 문제가 아니라 리소스 번들에 대한 색인을 생성하는 열거형 상수를 사용하여 현지화된 메시지에 액세스하도록 설계되었습니다.

나는 동일한 "템플릿" 열거형 코드를 모든 곳에 복사하여 붙여넣고 있음을 발견했습니다.중복을 피하기 위한 내 솔루션은 열거형 상수 이름과 생성자 인수가 포함된 XML 구성 파일을 허용하는 코드 생성기입니다.출력은 "중복" 동작이 포함된 Java 소스 코드입니다.

이제는 중복된 코드 전체가 아닌 구성 파일과 생성기를 유지 관리합니다.열거형 소스 코드가 있었던 모든 곳에 이제 XML 구성 파일이 있습니다.내 빌드 스크립트는 오래된 생성 파일을 감지하고 코드 생성기를 호출하여 열거형 코드를 생성합니다.

이 구성요소를 볼 수 있습니다. 여기.복사하여 붙여넣은 템플릿이 인수분해됩니다. XSLT 스타일시트.그만큼 코드 생성기 스타일시트 변환을 실행합니다.안 입력 파일 생성된 열거형 소스 코드에 비해 매우 간결합니다.

HTH,
그렉

불행히도, 나는 이것을 할 수 있는 방법이 없다고 생각합니다.가장 좋은 방법은 emum을 완전히 포기하고 기존 클래스 확장과 정적 멤버를 사용하는 것입니다.그렇지 않으면 해당 코드를 복제하는 데 익숙해집니다.죄송합니다.

코드별로 열거형을 로드하는 유형이 안전한 유틸리티 클래스를 만듭니다.

인터페이스는 다음과 같습니다.

public interface CodeableEnum {
    String getCode();
}

유틸리티 클래스는 다음과 같습니다.

import java.lang.reflect.InvocationTargetException;


public class CodeableEnumUtils {
    @SuppressWarnings("unchecked")
    public static <T extends CodeableEnum>  T getByCode(String code, Class<T> enumClass) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        T[] allValues = (T[]) enumClass.getMethod("values", new Class[0]).invoke(null, new Object[0]);
        for (T value : allValues) {
            if (value.getCode().equals(code)) {
                return value;
            }
        }
        return null;
}

}

사용법을 보여주는 테스트 사례:

import junit.framework.TestCase;


public class CodeableEnumUtilsTest extends TestCase {
    public void testWorks() throws Exception {
    assertEquals(A.ONE, CodeableEnumUtils.getByCode("one", A.class));
      assertEquals(null, CodeableEnumUtils.getByCode("blah", A.class));
    }

enum A implements CodeableEnum {
    ONE("one"), TWO("two"), THREE("three");

    private String code;

    private A(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }   
}
}

이제 getCode() 메서드만 복제하고 있으며 getByCode() 메서드는 한 곳에 있습니다.단일 RuntimeException으로 모든 예외를 래핑하는 것도 좋을 수 있습니다. :)

여기에 또 다른 해결책이 있습니다.

interface EnumTypeIF {
String getValue();

EnumTypeIF fromValue(final String theValue);

EnumTypeIF[] getValues();

class FromValue {
  private FromValue() {
  }

  public static EnumTypeIF valueOf(final String theValue, EnumTypeIF theEnumClass) {

    for (EnumTypeIF c : theEnumClass.getValues()) {
      if (c.getValue().equals(theValue)) {
        return c;
      }
    }
    throw new IllegalArgumentException(theValue);
  }
}

비결은 내부 클래스를 사용하여 "전역 메서드"를 보유할 수 있다는 것입니다.

나에게는 꽤 잘 작동했습니다.좋아, 3 가지 방법을 구현해야하지만 이러한 방법은 대표단 일뿐입니다.

실제로 런타임 유형 정보를 구현하고 있는 것 같습니다.Java는 이를 언어 기능으로 제공합니다.

RTTI나 반사를 찾아보는 것이 좋습니다.

나는 이것이 가능하다고 생각하지 않습니다.그러나 열거형 값의 이름을 코드로 사용하려는 경우 열거형의 valueOf(String name) 메서드를 사용할 수 있습니다.

정적 일반 메소드는 어떻습니까?열거형의 getByCode() 메소드 내에서 이를 재사용하거나 간단히 직접 사용할 수 있습니다.나는 항상 열거형에 대해 정수 ID를 사용하므로 getById() 메서드는 다음 작업만 수행합니다.값()[id]를 반환합니다.훨씬 빠르고 간단합니다.

정말로 상속을 원한다면, 할 수 있다는 것을 잊지 마세요 열거형 패턴을 직접 구현해 보세요., 나쁜 오래된 Java 1.4 시절처럼요.

내가 원하는 것에 가장 가까운 것은 IntelliJ에서 일반 코드(enum의 valueOf(String name) 사용)를 '구현'하는 템플릿을 만드는 것이었습니다.완벽하지는 않지만 꽤 잘 작동합니다.

특정 경우에 getCode() / getByCode(String code) 메소드는 모든 열거형에서 제공되는 toString() / valueOf(String value) 메소드의 동작에 대해 (완곡하게 말하면) 매우 닫힌 것처럼 보입니다.왜 사용하고 싶지 않습니까?

또 다른 해결책은 열거형 자체에 아무것도 넣지 않고 각 열거형에 대해 양방향 맵 Enum <-> 코드를 제공하는 것입니다.예를 들어사용 불변 BiMap 이를 위해 Google 컬렉션에서 제공됩니다.

그렇게 하면 중복된 코드가 전혀 없습니다.

예:

public enum MYENUM{
  VAL1,VAL2,VAL3;
}

/** Map MYENUM to its ID */
public static final ImmutableBiMap<MYENUM, Integer> MYENUM_TO_ID = 
new ImmutableBiMap.Builder<MYENUM, Integer>().
put(MYENUM.VAL1, 1).
put(MYENUM.VAL2, 2).
put(MYENUM.VAL3, 3).
build();

제 생각에는 이것이 반영 없이, 열거형에 추가 래퍼를 추가하지 않고도 가장 쉬운 방법이 될 것입니다.

열거형이 구현하는 인터페이스를 만듭니다.

public interface EnumWithId {

    public int getId();

}

그런 다음 도우미 클래스에서 다음과 같은 메서드를 만듭니다.

public <T extends EnumWithId> T getById(Class<T> enumClass, int id) {
    T[] values = enumClass.getEnumConstants();
    if (values != null) {
        for (T enumConst : values) {
            if (enumConst.getId() == id) {
                return enumConst;
            }
        }
    }

    return null;
}

이 방법은 다음과 같이 사용될 수 있습니다.

MyUtil.getInstance().getById(MyEnum.class, myEnumId);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top