inheritance公共接口的枚举中的代码重复

我有几个符合常见界面的枚举:

interface TableColumns { String getColumnName(); int getColumnIndex(); ColumnType getColumnType(); boolean isEditable(); int getColumnWidth(); } 

典型的实现是:

 enum PointsTableColumns implements TrendTableColumns { POINTS_COLUMN("points_column", false, ColumnType.TEXT, 400, 0); private String columnName; private boolean editable; private ColumnType columnType; private int columnWidth; private int columnIndex; private PointsTableColumns (String columnName, boolean editable, ColumnType columnType, int columnWidth, int columnIndex) { this.columnName = columnName; this.editable = editable; this.columnType = columnType; this.columnWidth = columnWidth; this.columnIndex = columnIndex; } public boolean isEditable() { return editable; } public int getColumnIndex() { return columnIndex; } public String getColumnName() { return columnName; } public int getColumnWidth() { return columnWidth; } public ColumnType getcolumnType() { return columnType; } } 

我有几个这样的实现(10+),每个都有多个几乎不同的值。 现在,问题是我在这里看到了很多代码重复,因为所有实现中的方法都是逐字相同的。 我知道在Java中这几乎是不可能的,因为枚举不能扩展实现。 我需要的是一个建议或不同的策略,可以更清洁的方式完成。 是否已有一些关于此的现有模式?

如果您可以使用一个级别的间接,那么我在下面介绍的方法会将重复的代码减少到最小。

首先,考虑以下供应商界面及其内部类:

 public interface PropertiesSupplier { Properties properties(); public static final class Properties { private final int value1; private final String value2; private final double value3; private Properties(int value1, String value2, double value3) { this.value1 = value1; this.value2 = value2; this.value3 = value3; } public static Properties of(int value1, String value2, double value3) { return new Properties(value1, value2, value3); } public int getValue1() { return this.value1; } public String getValue2() { return this.value2; } public double getValue3() { return this.value3; } @Override public String toString() { return "Properties [value1=" + this.value1 + ", value2=" + this.value2 + ", value3=" + this.value3 + "]"; } } } 

这里没什么神奇的。 内部类只是一个带有private final字段的bean,一个用于初始化它们的私有构造函数,public getter,一个工厂方法和一个覆盖toString()方法。 该接口仅定义一个返回内部类实例的方法。 请注意,内部类是最终的。 我们的想法是强制实现不变性,以便不允许其属性发生变化。

然后,让我们创建几个将实现此接口的枚举。 让我们从MyEnum1开始,它定义了两个值:

 public enum MyEnum1 implements PropertiesSupplier { ENUM_1_CONST_1(Properties.of(1, "hello", 0.123)), ENUM_1_CONST_2(Properties.of(2, "goodbye", 7.54)); private final Properties p; private MyEnum1(Properties p) { this.p = p; } @Override public Properties properties() { return this.p; } } 

接下来是MyEnum2 ,它只定义了一个值:

 public enum MyEnum2 implements PropertiesSupplier { ENUM_2_CONST_1(Properties.of(9, "hey dude", 547.21578)); private final Properties p; private MyEnum2(Properties p) { this.p = p; } @Override public Properties properties() { return this.p; } } 

如您所见,两个枚举都实现了PropertiesSupplier接口,因此它们必须为Properties properties()方法提供实现。 为了符合这一点,他们必须封装他们在构造函数中接收的Properties实例。

所以现在,在这个间接之后,在所有枚举中重复的唯一代码只是Properties字段,接收它作为参数的构造函数及其getter方法。

这是一个展示如何使用枚举的示例:

 MyEnum1 e1 = MyEnum1.ENUM_1_CONST_2; MyEnum2 e2 = MyEnum2.ENUM_2_CONST_1; System.out.println(e1.name() + " - " + e1.properties()); System.out.println(e2.name() + " - " + e2.properties()); 

此代码生成以下输出

 ENUM_1_CONST_2 - Properties [value1=2, value2=goodbye, value3=7.54] ENUM_2_CONST_1 - Properties [value1=9, value2=hey dude, value3=547.21578] 

您的所有枚举似乎都是单个值。 你应该将它们组合成一个enum

 enum TableColumns { POINTS("points_column", false, ColumnType.TEXT, 400, 0), FOO("foo_column", true, ColumnType.TXT, 123, 0), BAR("bar_column", true, ColumnType.TXT, 123, 0) ; ...rest is the same as your old POINTS_COLUMN } 

您应该考虑使用类并实现此方法以获取所有常量值,如枚举:

 public class Utils { public static  List values() { java.util.List result = new ArrayList<>(); Field[] fields = Bike.class.getFields(); for (Field field : fields) { if (field.getModifiers() == (Modifier.PUBLIC ^ Modifier.STATIC ^ Modifier.FINAL) && field.getType().equals(Bike.class)) { try { result.add((T) field.get(null)); } catch (IllegalAccessException e) { e.printStackTrace(); } } } return result; } } 

示例类:

 public class Bike { public final static Bike HONDA = new Bike("Honda"), SUZUKI = new Bike("Suzuki"), YAMAHA = new Bike("Yamaha"); private String name; public Bike(String name) { this.name = name; } public static List values() { return Utils.values(); } public static void main(String[] args) { System.out.println(values()); } } 

您可以使用组合而不是inheritance,将公共代码放在成为枚举属性的基本组件中。 此解决方案还引入了一个间接级别,并且每个新的枚举类需要4行样板代码。

例:

 /* * Example of sharing common code between enum classes wityh same 'structure' using * an EnumBase component. * This is a work-around on the restriction that enum cannot inherit from other classes */ package provajava; /** * * The base class wich contains the shared code * In this example we want to define many enums * which are composed of a field 'code' and a field 'name' */ class EnumBase { public EnumBase( int code, String name ) { theCode = code; theName = name; } // The attributes can be declared final public // In this case you do not need getters // but you still make sure that they cannot be changed outside the constructor final public int theCode; final public String theName; } public class TestEnum2 { /** * A first enum class */ enum BOOLEAN { TRUE ( 1, "True "), FALSE (2, "False"); // This is boilerplate code that need to be repeated for each enum // Annoying, but is much shorter than shared code, especially if there are many enum values final public EnumBase base; BOOLEAN (int c, String n) { base = new EnumBase(c,n ); } } /** * A second enum class */ enum NUMBER { ONE ( 1, "One"), TWO (2, "Two"), THREE(3, "Three"); // This is boilerplate code that need to be repeated for each enum // Annoying, but is much shorter than repeating shared code, especially if there are many enum values final public EnumBase base; NUMBER (int c, String n) { base = new EnumBase(c,n ); } } public static void main(String args[] ) { BOOLEAN b = BOOLEAN.FALSE; NUMBER n = NUMBER.TWO; System.out.println( b + "->" + b.base.theCode + "," + b.base.theName ); System.out.println( n + "->" + n.base.theCode + "," + n.base.theName ); // n.base.theCode = 2; // ERROR : cannot assign to a final variable // n.base = new EnumBase( 1, "TWELVE"); // ERROR : cannot assign to a final variable } }