2016-11-10 1 views
-1

접근법은 매우 간단합니다. B가 B의 ENUM A를 서브 클래스 화하여 B가 A의 모든 값을 상속 받기를 원합니다.ENUM 서브 클래 싱

이 게시물 Can enums be subclassed to add new elements?은 이미 다양한 솔루션 (광산 포함)을 설명하고 있습니다. 그러나 나는 나의 마지막 포스트가 모든 대답 후에 읽혀질 것이라고 생각하지 않는다. 그래서 나는이 해결책이 보이고 어쩌면 사용되기를 바라는 나의 대답으로 새로운 포스트를 만들었다.

+1

다른 질문에는 300 개 이상의 상행승이 있습니다. 정답은 여기보다 더 많이 보입니다. – khelwood

+2

기존 질문을 게시하고 있습니까? 그것이 바로 복제물의 정의입니다. 이미 존재하는 답변을 게시하고 있습니까? 왜 그런가 - 당신이 접근 방식을 좋아하고 다른 대답으로 주어진다면, 그것을 upvote. –

+0

네가하는 말을 이해한다. 나는 단지 현실적이다. 내 답변이 이미 수백 표의 답변에 대해 상향 조정되었는데 그 답변이 이미 올바른 것으로 표시되어있을 가능성이 얼마나 높습니까? 나 자신은 꼭 아래까지 읽지 않을 것이다. – Dr4gon

답변

0

인터페이스 접근법을 따르고 하위 클래스로 분류하는이 우아한 접근 방식을 동료와 공유하고 싶습니다.

여기서 사용자 지정 예외를 사용하므로이 코드는 예외로 바꾸지 않으면 컴파일되지 않습니다.

설명서는 광범위하며 대부분 사용자에게 이해하기를 바랍니다.

모든 하위 클래스가있는 enum이 구현해야하는 인터페이스입니다.

public interface Parameter { 
    /** 
    * Retrieve the parameters name. 
    * 
    * @return the name of the parameter 
    */ 
    String getName(); 

    /** 
    * Retrieve the parameters type. 
    * 
    * @return the {@link Class} according to the type of the parameter 
    */ 
    Class<?> getType(); 

    /** 
    * Matches the given string with this parameters value pattern (if applicable). This helps to find 
    * out if the given string is a syntactically valid candidate for this parameters value. 
    * 
    * @param valueStr <i>optional</i> - the string to check for 
    * @return <code>true</code> in case this parameter has no pattern defined or the given string 
    *   matches the defined one, <code>false</code> in case <code>valueStr</code> is 
    *   <code>null</code> or an existing pattern is not matched 
    */ 
    boolean match(final String valueStr); 

    /** 
    * This method works as {@link #match(String)} but throws an exception if not matched. 
    * 
    * @param valueStr <i>optional</i> - the string to check for 
    * @throws ArgumentException with code 
    *   <dl> 
    *   <dt>PARAM_MISSED</dt> 
    *   <dd>if <code>valueStr</code> is <code>null</code></dd> 
    *   <dt>PARAM_BAD</dt> 
    *   <dd>if pattern is not matched</dd> 
    *   </dl> 
    */ 
    void matchEx(final String valueStr) throws ArgumentException; 

    /** 
    * Parses a value for this parameter from the given string. This method honors the parameters data 
    * type and potentially other criteria defining a valid value (e.g. a pattern). 
    * 
    * @param valueStr <i>optional</i> - the string to parse the parameter value from 
    * @return the parameter value according to the parameters type (see {@link #getType()}) or 
    *   <code>null</code> in case <code>valueStr</code> was <code>null</code>. 
    * @throws ArgumentException in case <code>valueStr</code> is not parsable as a value for this 
    *   parameter. 
    */ 
    Object parse(final String valueStr) throws ArgumentException; 

    /** 
    * Converts the given value to its external form as it is accepted by {@link #parse(String)}. For 
    * most (ordinary) parameters this is simply a call to {@link String#valueOf(Object)}. In case the 
    * parameter types {@link Object#toString()} method does not return the external form (e.g. for 
    * enumerations), this method has to be implemented accordingly. 
    * 
    * @param value <i>mandatory</i> - the parameters value 
    * @return the external form of the parameters value, never <code>null</code> 
    * @throws InternalServiceException in case the given <code>value</code> does not match 
    *   {@link #getType()} 
    */ 
    String toString(final Object value) throws InternalServiceException; 
} 

구현하는 ENUM 기본 클래스.

public enum Parameters implements Parameter { 
    /** 
    * ANY ENUM VALUE 
    */ 
    VALUE(new ParameterImpl<String>("VALUE", String.class, "[A-Za-z]{3,10}")); 

    /** 
    * The parameter wrapped by this enum constant. 
    */ 
    private Parameter param; 

    /** 
    * Constructor. 
    * 
    * @param param <i>mandatory</i> - the value for {@link #param} 
    */ 
    private Parameters(final Parameter param) { 
    this.param = param; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public String getName() { 
    return this.param.getName(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Class<?> getType() { 
    return this.param.getType(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean match(final String valueStr) { 
    return this.param.match(valueStr); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void matchEx(final String valueStr) { 
    this.param.matchEx(valueStr); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Object parse(final String valueStr) throws ArgumentException { 
    return this.param.parse(valueStr); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public String toString(final Object value) throws InternalServiceException { 
    return this.param.toString(value); 
    } 
} 

기본 클래스에서 "상속받은"하위 클래스 ENUM.

public enum ExtendedParameters implements Parameter { 
    /** 
    * ANY ENUM VALUE 
    */ 
    VALUE(my.package.name.VALUE); 

    /** 
    * EXTENDED ENUM VALUE 
    */ 
    EXTENDED_VALUE(new ParameterImpl<String>("EXTENDED_VALUE", String.class, "[0-9A-Za-z_.-]{1,20}")); 

    /** 
    * The parameter wrapped by this enum constant. 
    */ 
    private Parameter param; 

    /** 
    * Constructor. 
    * 
    * @param param <i>mandatory</i> - the value for {@link #param} 
    */ 
    private Parameters(final Parameter param) { 
    this.param = param; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public String getName() { 
    return this.param.getName(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Class<?> getType() { 
    return this.param.getType(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean match(final String valueStr) { 
    return this.param.match(valueStr); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void matchEx(final String valueStr) { 
    this.param.matchEx(valueStr); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Object parse(final String valueStr) throws ArgumentException { 
    return this.param.parse(valueStr); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public String toString(final Object value) throws InternalServiceException { 
    return this.param.toString(value); 
    } 
} 

마지막으로 일부 유틸리티를 추가하는 일반 ParameterImpl.

public class ParameterImpl<T> implements Parameter { 
    /** 
    * The default pattern for numeric (integer, long) parameters. 
    */ 
    private static final Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+"); 

    /** 
    * The default pattern for parameters of type boolean. 
    */ 
    private static final Pattern BOOLEAN_PATTERN = Pattern.compile("0|1|true|false"); 

    /** 
    * The name of the parameter, never <code>null</code>. 
    */ 
    private final String name; 

    /** 
    * The data type of the parameter. 
    */ 
    private final Class<T> type; 

    /** 
    * The validation pattern for the parameters values. This may be <code>null</code>. 
    */ 
    private final Pattern validator; 

    /** 
    * Shortcut constructor without <code>validatorPattern</code>. 
    * 
    * @param name <i>mandatory</i> - the value for {@link #name} 
    * @param type <i>mandatory</i> - the value for {@link #type} 
    */ 
    public ParameterImpl(final String name, final Class<T> type) { 
    this(name, type, null); 
    } 

    /** 
    * Constructor. 
    * 
    * @param name <i>mandatory</i> - the value for {@link #name} 
    * @param type <i>mandatory</i> - the value for {@link #type} 
    * @param validatorPattern - <i>optional</i> - the pattern for {@link #validator} 
    *   <dl> 
    *   <dt style="margin-top:0.25cm;"><i>Note:</i> 
    *   <dd>The default validation patterns {@link #NUMBER_PATTERN} or 
    *   {@link #BOOLEAN_PATTERN} are applied accordingly. 
    *   </dl> 
    */ 
    public ParameterImpl(final String name, final Class<T> type, final String validatorPattern) { 
    this.name = name; 
    this.type = type; 
    if (null != validatorPattern) { 
     this.validator = Pattern.compile(validatorPattern); 

    } else if (Integer.class == this.type || Long.class == this.type) { 
     this.validator = NUMBER_PATTERN; 
    } else if (Boolean.class == this.type) { 
     this.validator = BOOLEAN_PATTERN; 
    } else { 
     this.validator = null; 
    } 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean match(final String valueStr) { 
    if (null == valueStr) { 
     return false; 
    } 
    if (null != this.validator) { 
     final Matcher matcher = this.validator.matcher(valueStr); 
     return matcher.matches(); 
    } 
    return true; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void matchEx(final String valueStr) throws ArgumentException { 
    if (false == this.match(valueStr)) { 
     if (null == valueStr) { 
     throw ArgumentException.createEx(ErrorCode.PARAM_MISSED, "The value must not be null", 
      this.name); 
     } 
     throw ArgumentException.createEx(ErrorCode.PARAM_BAD, "The value must match the pattern: " 
      + this.validator.pattern(), this.name); 
    } 
    } 

    /** 
    * Parse the parameters value from the given string value according to {@link #type}. Additional 
    * the value is checked by {@link #matchEx(String)}. 
    * 
    * @param valueStr <i>optional</i> - the string value to parse the value from 
    * @return the parsed value, may be <code>null</code> 
    * @throws ArgumentException in case the parameter: 
    *   <ul> 
    *   <li>does not {@link #matchEx(String)} the {@link #validator}</li> 
    *   <li>cannot be parsed according to {@link #type}</li> 
    *   </ul> 
    * @throws InternalServiceException in case the type {@link #type} cannot be handled. This is a 
    *   programming error. 
    */ 
    @Override 
    public T parse(final String valueStr) throws ArgumentException, InternalServiceException { 
    if (null == valueStr) { 
     return null; 
    } 
    this.matchEx(valueStr); 

    if (String.class == this.type) { 
     return this.type.cast(valueStr); 
    } 
    if (Boolean.class == this.type) { 
     return this.type.cast(Boolean.valueOf(("1".equals(valueStr)) || Boolean.valueOf(valueStr))); 
    } 
    try { 
     if (Integer.class == this.type) { 
     return this.type.cast(Integer.valueOf(valueStr)); 
     } 
     if (Long.class == this.type) { 
     return this.type.cast(Long.valueOf(valueStr)); 
     } 
    } catch (final NumberFormatException e) { 
     throw ArgumentException.createEx(ErrorCode.PARAM_BAD, "The value cannot be parsed as " 
      + this.type.getSimpleName().toLowerCase() + ".", this.name); 
    } 

    return this.parseOther(valueStr); 
    } 

    /** 
    * Field access for {@link #name}. 
    * 
    * @return the value of {@link #name}. 
    */ 
    @Override 
    public String getName() { 
    return this.name; 
    } 

    /** 
    * Field access for {@link #type}. 
    * 
    * @return the value of {@link #type}. 
    */ 
    @Override 
    public Class<T> getType() { 
    return this.type; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public final String toString(final Object value) throws InternalServiceException { 
    if (false == this.type.isAssignableFrom(value.getClass())) { 
     throw new InternalServiceException(ErrorCode.PANIC, 
      "Parameter.toString(): Bad type of value. Expected {0} but is {1}.", this.type.getName(), 
      value.getClass().getName()); 
    } 
    if (String.class == this.type || Integer.class == this.type || Long.class == this.type) { 
     return String.valueOf(value); 
    } 
    if (Boolean.class == this.type) { 
     return Boolean.TRUE.equals(value) ? "1" : "0"; 
    } 

    return this.toStringOther(value); 
    } 

    /** 
    * Parse parameter values of other (non standard types). This method is called by 
    * {@link #parse(String)} in case {@link #type} is none of the supported standard types (currently 
    * String, Boolean, Integer and Long). It is intended for extensions. 
    * <dl> 
    * <dt style="margin-top:0.25cm;"><i>Note:</i> 
    * <dd>This default implementation always throws an InternalServiceException. 
    * </dl> 
    * 
    * @param valueStr <i>mandatory</i> - the string value to parse the value from 
    * @return the parsed value, may be <code>null</code> 
    * @throws ArgumentException in case the parameter cannot be parsed according to {@link #type} 
    * @throws InternalServiceException in case the type {@link #type} cannot be handled. This is a 
    *   programming error. 
    */ 
    protected T parseOther(final String valueStr) throws ArgumentException, InternalServiceException { 
    throw new InternalServiceException(ErrorCode.PANIC, 
     "ParameterImpl.parseOther(): Unsupported parameter type: " + this.type.getName()); 
    } 

    /** 
    * Convert the values of other (non standard types) to their external form. This method is called 
    * by {@link #toString(Object)} in case {@link #type} is none of the supported standard types 
    * (currently String, Boolean, Integer and Long). It is intended for extensions. 
    * <dl> 
    * <dt style="margin-top:0.25cm;"><i>Note:</i> 
    * <dd>This default implementation always throws an InternalServiceException. 
    * </dl> 
    * 
    * @param value <i>mandatory</i> - the parameters value 
    * @return the external form of the parameters value, never <code>null</code> 
    * @throws InternalServiceException in case the given <code>value</code> does not match 
    *   {@link #getClass()} 
    */ 
    protected String toStringOther(final Object value) throws InternalServiceException { 
    throw new InternalServiceException(ErrorCode.PANIC, 
     "ParameterImpl.toStringOther(): Unsupported parameter type: " + this.type.getName()); 
    } 
}