Effective Java 34 Emulate extensible enums with interfaces
|
Advantage |
Disadvantage |
|
|
Enum types |
Clarity Safety Ease of maintenance. |
None extensibility |
|
Typesafe enum pattern(Interfaces to emulate extensible enums) |
Extensibility |
No good way to enumerate all of the elements of a base type and its extension. Extensibility would complicate many aspects of the design and implementation. Implementations cannot be inherited from one enum type to another. |
Scenario
Sometimes it is desirable to let the users of an API provide their own operations, effectively extending the set of operations provided by the API.
Compelling use case for extensible enumerated type -- Operation codes/ opcodes.
Usage
- Pass a single instance of an "extension enum" anywhere a "base enum" is expected.
/**
* Demo for "34 Emulate extensible enums with interfaces".
*/
package com.effectivejava.EnumAnnotations;
/**
* @author Kaibo
*
*/
public interface Operation {
double apply(double x, double y);
}
/**
* Demo for the "34 Emulate extensible enums with interfaces".
*/
package com.effectivejava.EnumAnnotations;
import java.util.HashMap;
import java.util.Map;
/**
* @author Kaibo
*
*/
public enum BaseOperation implements Operation {
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;
BaseOperation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
public abstract double apply(double x, double y);
// Implementing a fromString method on an enum type
private static final Map<String, BaseOperation> stringToEnum = new HashMap<String, BaseOperation>();
static { // Initialize map from constant name to enum constant
for (BaseOperation op : values())
stringToEnum.put(op.toString(), op);
}
// Returns BaseOperation for string, or null if string is invalid
public static BaseOperation fromString(String symbol) {
return stringToEnum.get(symbol);
}
}
- Pass in an entire extension enum type and use its elements in addition to or instead of those of the base type.
/**
* Demo for the "34 Emulate extensible enums with interfaces".
*/
package com.effectivejava.EnumAnnotations;
/**
* @author Kaibo
*
*/
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;
}
}
Note
- Passing the extended enums between methods.
- Bounded type token
public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
double y = Double.parseDouble(args[1]);
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));
}
b. Passing with Collection<? Extends Operation>
public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
double y = Double.parseDouble(args[1]);
test(Arrays.asList(ExtendedOperation.values()), x, y);
}
private static void test(Collection<? extends Operation> opSet, double x, double y) {
for (Operation op : opSet)
System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
}
2. The logic to store and retrieve the symbol associated with an operation is duplicated in BasicOperation and ExtendedOperation. In this case it doesn't matter because very little code is duplicated. If there were a larger amount of shared functionality, you could encapsulate it in a helper class or a static helper method to eliminate the code duplication.
Summary
While you cannot write an extensible enum type, you can emulate it by writing an interface to go with a basic enum type that implements the interface.
Effective Java 34 Emulate extensible enums with interfaces的更多相关文章
- Effective Java Index
Hi guys, I am happy to tell you that I am moving to the open source world. And Java is the 1st langu ...
- 《Effective Java》读书笔记 - 6.枚举和注解
Chapter 6 Enums and Annotations Item 30: Use enums instead of int constants Enum类型无非也是个普通的class,所以你可 ...
- Effective Java 目录
<Effective Java>目录摘抄. 我知道这看起来很糟糕.当下,自己缺少实际操作,只能暂时摘抄下目录.随着,实践的增多,慢慢填充更多的示例. Chapter 2 Creating ...
- 【Effective Java】阅读
Java写了很多年,很惭愧,直到最近才读了这本经典之作<Effective Java>,按自己的理解总结下,有些可能还不够深刻 一.Creating and Destroying Obje ...
- Effective Java 第三版——34. 使用枚举类型替代整型常量
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——38. 使用接口模拟可扩展的枚举
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版笔记(目录)
<Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时 ...
- [Effective Java]第八章 通用程序设计
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- Effective Java通俗理解(下)
Effective Java通俗理解(上) 第31条:用实例域代替序数 枚举类型有一个ordinal方法,它范围该常量的序数从0开始,不建议使用这个方法,因为这不能很好地对枚举进行维护,正确应该是利用 ...
随机推荐
- python 在sublime 中的配置
首先可以先装package control 方法——按ctrl+`,然后在命令行里复制粘贴以下代码, import urllib2,os;pf='Package Control.sublime-pac ...
- C# 只启动一个实例完全解决方案
工作上经常会遇到"程序只能启动一个实例"这样的需求. 我想,这样的需求应该很普遍,所以没打算去动脑筋,去找谷歌问下就得了,用下来发现,不是这里不爽就是那里不行. 先说下我详细的几点 ...
- WebGL 3D on iOS8 正式版
今天iOS8终于正式发布了,升级了手头设备后对我来说最重要的就是测试WebGL的3D是否真的能跑苹果的系统了,跑了多个HT for Web的3D例子都非常流畅,比Android刚支持WebGL时好太多 ...
- MyBatis动态SQL使用,传入参数Map中的Key判断
<select id="" parameterType="Map" resultMap="commodityResultMap" &g ...
- 重构13天 抽取方法对象(Extract Method Object)
理解:本文中的“提取方法对象”是指当你发现一个方法中存在过多的局部变量时,你可以通过使用“提取方法对象”重构来引入一些方法,每个方法完成任务的一个步骤,这样可以使得程序变得更具有可读性. 详解:如下代 ...
- 循序渐进开发WinForm项目(2)--项目代码的分析
随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...
- 在一个XAML中点击按钮,界面跳转到另一个XAML界面方法
private void ButtonGo_camerapage(object sender, RoutedEventArgs e) { this.Content = new cameraPage() ...
- 【Bootstrap基础学习】05 Bootstrap学习总结
好吧,Copy了几天,这个总结算是把我对Bootstrap的一些理解写一下吧. Bootstrap只是一套别人写好的前端框架,直接拿来用就好. 不过对于专业的前端而言,如果不去把所有的代码都看一遍来理 ...
- Run python as a daemon process
I am using `&`: why isn't the process running in the background? No problem. We won't show y ...
- 为什么.NET感觉上比Java差一点
其实,我本人很喜欢.NET技术.工作经历中,大部分时间也在使用.NET开发. 这几年,由于工作的原因,开始进入Java+Linux世界. 今年,开始学习Python和Scala. 使用.NET时,有种 ...