2010-03-10 6 views
1

Excel 시트에서 /로 DB 테이블을 내보내고 가져 오는 기존 앱의 일부를 리팩토링하고 있습니다. 각 테이블에 대해 Formatter 서브 클래스가 있으며, 테이블의 정의를 제공합니다. 즉, 컬럼의 수와 각 컬럼의 이름, 형식 및 유효성 검사기는 무엇입니까? 이 데이터를 제공하는 getter는 테이블을 내보내거나 가져 오는 Template Method에 의해 호출됩니다. 열 데이터를 열거 형으로 추출하여 코드를 크게 단순화했습니다. 나는 다른 각 ColumnNUM_COLUMNS 및 열거 값을 제외하고 동일 코드를 포함하고있는 다스 같은 클래스에 대해이 지금정적 구성원으로 Java enum을 일반화하는 방법은 무엇입니까?

public class DamageChargeFormatter extends BaseFormatter { 
    public static final int NUM_COLUMNS = 7; 

    public enum Column { 
     VEHICLE_GROUP(0, "Vehicle Group", /* more params */), 
     NAME_OF_PART(1, "Name of Part", /* more params */), 
     //... 
     LOSS_OF_USE(6, "Loss of Use", /* more params */); 

     private static final Map<Integer, Column> intToColumn = new HashMap<Integer, Column>(); 

     static { 
      for (Column type : values()) { 
       intToColumn.put(type.getIndex(), type); 
      } 
     } 

     public static TableColumn valueOf(int index) { 
      return intToColumn.get(index); 
     } 

     private int index; 
     private String name; 

     Column(int index, String name, /* more params */) { 
      this.index = index; 
      this.name = name; 
      //... 
     } 

     public int getIndex() { return index; } 

     public String getName() { return name; } 

     // more members and getters... 
    } 

    protected String getSheetName() { 
     return "Damage Charges"; 
    } 

    public String getColumnName(int columnNumber) { 
     TableColumn column = Column.valueOf(columnNumber); 

     if (column != null) { 
      return column.getName(); 
     } 
     return null; 
    } 

    // more getters... 

    protected int getNumColumns() { 
     return NUM_COLUMNS; 
    } 

    protected boolean isVariableColumnCount() { 
     return false; 
    } 
} 

: 포맷터는 지금과 같이 (간결함을 위해 생략 몇 가지 세부 사항)를 찾습니다 . 어떻게 든 이것을 일반화 할 수있는 방법이 있습니까? 가장 큰 장애물은 정적 인 Column.valueOf() 방법과 고정 상수 NUM_COLUMNS입니다. 후자에 대한 또 다른 관심사는 실제로는 한 수준 높은 추상화 즉 테이블에 대한 것이고 개별 열에 대한 추상화에 속하지 않는다는 것입니다. 어떻게 든 이것을 일반 솔루션에 통합하는 것이 좋을 것입니다.

기술적으로 나는 기본 인터페이스 (아래 TableColumn)와 반사를 사용하여이 문제를 해결할 수 있었지만, 런타임 오류를 컴파일하는 것과는 별개로 코드가 못 생겼습니다. 이 코드는 아직 검증되지 않은, 순수 실험이라고

public class GenericFormatter<E extends TableColumn> extends BaseFormatter { 
    private Method valueOfMethod; 

    public GenericFormatter(Class<E> columnClass) { 
     try { 
      valueOfMethod = columnClass.getDeclaredMethod("valueOf", Integer.class); 
     } catch (NoSuchMethodException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public String getColumnName(int columnNumber) { 
     try { 
      @SuppressWarnings("unchecked") 
      E elem = (E) valueOfMethod.invoke(columnNumber); 

      if (elem != null) { 
       return elem.getName(); 
      } 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
     return null; 
    } 

    //... 
} 

...

는 더 좋은, 깨끗하고 안전한 방법이 있습니까?

답변

1

수있다, 이런 식으로 뭔가 :

public class TableMetadata<E extends Enum & TableColumn> { 
    private Map<Integer, TableColumn> columns = new HashMap<Integer, TableColumn>(); 

    public TableMetadata(Class<E> c) { 
     for (E e: c.getEnumConstants()) { 
      columns.put(e.getIndex(), e); 
     } 
    } 

    public String getColumnName(int index) { 
     return columns.get(index).getName(); 
    } 
} 

public class GenericFormatter<E extends TableColumn> extends BaseFormatter { 
    private TableMetadata<E> m; 

    public GenericFormatter(TableMetadata<E> m) { 
     this.m = m; 
    } 

    public String getColumnName(int columnNumber) { 
     return m.getColumnName(index); 
    } 

    //... 
} 

편집 :Enum 더 컴파일시 안전

+0

우수 아이디어에 대한 형식 매개 변수에 추가! 정적 룩업 방법이 열거 형 내부에 있다고 가정하고 맹목적으로 정신 박약함에 갇혔다는 것을 분명히했습니다. 감사! :-) –

관련 문제