EffectiveJava(34) -- 使用接口模拟可伸缩的枚举

来源:互联网 发布:windows应用软件开发 编辑:程序博客网 时间:2024/05/17 22:21

~~使用可伸缩性枚举模式会导致扩展实例的元素是基本类型的实例 , 但是基本类型的实例却不是扩展类型的元素 , 这样得到的数据很是混乱 . 所以可伸缩性枚举模式是不被 Java 语言支持的 , 而且直至目前 , 并没有很好的办法来枚举基本类型的所有元素及其扩展 . 最终 , 可伸缩性会导致设计和实现的许多方面变得很复杂 .
但是 , 由于枚举类型可以通过给操作码类型和枚举定义接口来实现任意接口 , 我们依然可以通过其他办法变相实现可伸缩性枚举

/** * 虽然枚举类型是不能扩展的 , 但是可以通过接口类表示API中的操作的接口类型 .  * 你可以定义一个功能完全不同的枚举类型来实现这个接口 .   */public interface Operation {    double apply(double x,double y);}//它的一个实现类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;    }       @Override    public String toString(){        return symbol;    }}
//他的另一个实现类public enum ExtendedOperation implements Operation{    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;    ExtendedOperation(String symbol) {        this.symbol = symbol;    }    @Override    public String toString(){        return symbol;    }}

我们可以以编写多个实现类方式扩展 Operation 从侧面实现枚举的伸缩性

客户端代码

public static void main(String[] args) {        double x = 2;        double y = 4;        //将扩展过的操作类型的类的字面文字从main中传递给test方法来描述被扩展的集合        test(ExtendedOperation.class, x, y);    }    //不仅可以在任何需要"基本枚举"的地方单独传递一个"扩展枚举"的实例  //而且除了基本类型元素之外 , 还可以传递完整的扩展枚举类型 , 并使用它的元素 .     private static <T extends Enum<T> & Operation> void test(Class<T> opSet,double x,double y){        for(Operation op : opSet.getEnumConstants())            System.out.printf("%f %s %f= %f%n",x,op,y,op.apply(x, y));    }
在这里有必要解释一下 <T extends Enum<T> & Operation> 声明 . 它确保了 Class 对象既表示枚举由表示 Operation 的子类型,是便利元素和执行与每个元素相关联操作时所需要的 . 我们也可以用有限制的通配符类型来作为它的参数 , 如 :
public static void main(String[] args) {        double x = 2;        double y = 4;        //test(ExtendedOperation.class, x, y);        //这种方法允许调用者将多个实现类型的操作合并在一起,使得方法性更灵活,代码更清晰        test(Arrays.asList(Operation.values()),x,y);    }    //使用有限制的通配符作为opSet参数的类型    private static void test(Collection<? extends ExtendedOperation> opSet,double x ,double y){        for(ExtendedOperation op:opSet){            System.out.printf("%f %s %f= %f%n",x,op,y,op.apply(x, y));        }    }

使用接口模拟可伸缩枚举的时候 , 无法将实现从一个枚举类型集成到另一个枚举类型上

总结:虽然无法编写可扩展的枚举类型 , 但是可以通过编写接口以及实现该接口的基础枚举类型对它进行模拟 . 这样允许客户端编写自己的枚举来实现接口 . 如果 API 是根据接口编写的,那么在可以使用基础枚举类型的任何地方 , 也都可以使用这些枚举 .

2 0
原创粉丝点击