代码之家  ›  专栏  ›  技术社区  ›  Péter Török

如何用静态成员概括Java枚举?

  •  1
  • Péter Török  · 技术社区  · 14 年前

    我正在重构我们的遗留应用程序的一部分,它处理从/到excel表的db表的导出和导入。我们有一个 Formatter 为每个表提供子类,以提供该表的定义:它有多少列,以及每列的名称、格式和验证器。然后由导出/导入表的模板方法调用提供此数据的getter。我已经将列数据提取到枚举中,这大大简化了代码。格式化程序现在如下所示(为简洁起见省略了一些细节):

    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_COLUMNS 以及 Column 是不同的。有什么方法可以把它概括成这样吗?主要的障碍是静电 Column.valueOf() 方法与静态常数 数字列 . 后者的另一个关注点是,它实际上属于一个更高层次的抽象,即表,而不是单个列——以某种方式将其合并到通用解决方案中会更好。

    从技术上讲,我可以用一个基本接口来解决这个问题( 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 回复  |  直到 14 年前
        1
  •  1
  •   axtavt    14 年前

    可能是这样的:

    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 添加到类型参数以提高编译时安全性