簡體   English   中英

如何使用靜態成員泛化Java枚舉?

[英]How to genericize a Java enum with static members?

我正在重構遺留應用程序的一部分,該應用程序處理從/到Excel工作表的數據庫表的導出和導入。 我們為每個表都有一個Formatter子類,以提供該表的定義:它具有多少列,以及每列的名稱,格式和驗證器是什么。 然后,通過導出/導入表的模板方法調用提供此數據的吸氣劑。 我已經將列數據提取到一個枚舉中,這大大簡化了代碼。 格式化程序現在看起來像這樣(為簡潔起見,省略了一些詳細信息):

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

現在,我大約有十二個這樣的類,除了NUM_COLUMNSColumn的枚舉值不同之外,每個類都包含完全相同的代碼。 有什么辦法可以某種方式將其泛化嗎? 這樣做的主要障礙是靜態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;
    }

    //...
}

請注意,此代碼純粹是實驗性的,尚未經過測試...

有沒有更好,更清潔,更安全的方法?

可能是這樣的:

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添加到type參數以獲得更多的編譯時安全性

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM