第34条:用接口模拟可伸缩的枚举
虽然枚举类型是不可扩展的,但是接口类型则是可扩展的。它是用来表示API中的操作的接口类型。可以定义另一个枚举类型,它实现这个接口,并用新的类型的实例代替基本类型。
/**
* 34:用接口模拟可伸缩的枚举
* 枚举类型是不可扩展的,但是接口类型是可扩展的。使用接口,可以模拟可伸缩的枚举。
*/
public class EnumInterface {
private static <T extends Enum<T> & InterfaceDemo> void test(Class<T> opSet, double x, double y) {
for(InterfaceDemo op : opSet.getEnumConstants())
System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
}
public static void main(String[] args) {
double x = 2.0;
double y = 4.0;
test(ExtendedOperation.class, x, y);
}
}
//接口提取参数
interface InterfaceDemo {
double apply(double x, double y);
}
//原始计算器本来枚举已定型
enum BasicOperation implements InterfaceDemo {
PLUS("+") {
public double apply(double x, double y) {return x + y;}
},
MINUS("-") {
public double apply(double x, double y) {return x - y;}
},
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;
BasicOperation(String symbol) {
this.symbol = symbol;
}
public String toString() {
return symbol;
}
}
//扩展功能 同样实现 参数接口 达到扩展目的, 依赖倒转原则,细节依赖抽象。
enum ExtendedOperation implements InterfaceDemo {
EXP("^") {
public double apply(double x, double y) {return Math.pow(x, y);}
},
REMAINDER("%") {
public double apply(double x, double y) {return x % y;}
};
private final String symbol;
private ExtendedOperation(String symbol) {
this.symbol = symbol;
}
public String toString() {
return symbol;
}
}
用接口模拟可伸缩枚举有个小小的不足,即无法将实现从一个枚举类型继承到另一个枚举类型。 在上述Operation的示例中,保存和获取与某项操作相关联的符号的逻辑代码,可以复制到BasicOperation和ExtendedOperation中。在这个例子中是可以的,因为复制的代码非常少。如果共享功能比较多,则可以将他封装在一个辅助类或者静态辅助方法中,来避免代码的重复工作。
总而言之,虽然无法编写可扩展的枚举类型,却可以通过编写接口以及实现该接口的基础枚举类型,对他进行模拟。这样允许客户端编写自己的枚举来实现接口。如果API是根据接口编写的,那么在可以使用基础枚举类型的任何地方,也都可以使用这些枚举。