第38条:用接口模拟可扩展的枚举
主要解决Java枚举的一个局限性:枚举类型不能被继承。但在某些场景下,我们希望枚举具有一定的扩展性,允许第三方添加新的枚举常量。
解决方法,通过接口来拓展枚举。
接口 + 枚举
虽然枚举类型不是可扩展的,但接口类型却是可扩展的,它是用来表示 API 中的操作的接口类型,可以定义另 个枚举类型,它实现这个接口,并用这个新类型的实例代替基本类型。
java
// 步骤1:定义操作接口
public interface Operation {
double apply(double x, double y);
}
// 步骤2:基础枚举实现接口
public enum BasicOperation implements Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
};
private final String symbol;
BasicOperation(String symbol) { this.symbol = symbol; }
}
// 步骤3:扩展枚举(新的枚举实现同一接口)
public enum ExtendedOperation implements Operation {
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
public double apply(double x, double y) { return x / y; }
};
private final String symbol;
ExtendedOperation(String symbol) { this.symbol = symbol; }
}
使用
java
public class Main {
public static void main(String[] args) {
System.out.println(BasicOperation.PLUS.apply(1, 2));
System.out.println(BasicOperation.MINUS.apply(1, 2));
System.out.println(ExtendedOperation.TIMES.apply(1, 2));
System.out.println(ExtendedOperation.DIVIDE.apply(1, 2));
test(BasicOperation.class, 1, 2);
}
// 方法可以接受任何实现了Operation接口的枚举
public static <T extends Enum<T> & Operation> void test(
Class<T> opEnumType, double x, double y) {
for (Operation op : opEnumType.getEnumConstants()) {
System.out.printf("%f %s %f = %f%n",
x, op, y, op.apply(x, y));
}
}
}

也可以通过集合参数使用
java
// 可以混合使用不同枚举类型的操作
public static void testAll(Collection<? extends Operation> operations,
double x, double y) {
for (Operation op : operations) {
System.out.printf("%f %s %f = %f%n",
x, op, y, op.apply(x, y));
}
}
// 混合使用
testAll(Arrays.asList(BasicOperation.PLUS,
ExtendedOperation.TIMES), 10, 5);
总结
虽然无法编写可扩展的枚举类型,却可以通过编写接口以及实现该接口的基础枚举类型来对它进行模拟.