2010-03-10 82 views
1

我正在重構我們遺留應用程序的一部分,該應用程序處理從/到Excel工作表的導出和導入數據庫表。我們爲每個表提供了一個Formatter子類,以提供該表的定義:它有多少列,以及每列的名稱,格式和驗證程序是什麼。提供這些數據的獲取者然後通過導出/導入表格的模板方法調用。我已經將列數據提取到一個枚舉中,這大大簡化了代碼。格式化器現在看起來像這樣(一些細節不再贅述):如何用靜態成員泛型Java枚舉?

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在於NUM_COLUMNS和枚舉值相同的代碼是不同的。有什麼辦法來通用這種方式嗎?主要障礙是靜態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

好主意!你明確表示我陷入了一種精神r,,一味地假設靜態查找方法在枚舉中。謝謝! :-) – 2010-03-11 09:18:25