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开始,不建议使用这个方法,因为这不能很好地对枚举进行维护,正确应该是利用 ...
随机推荐
- MyBatis动态SQL使用,传入参数Map中的Key判断
<select id="" parameterType="Map" resultMap="commodityResultMap" &g ...
- Linq专题之创建Linq查询表达式
本节我们主要介绍一下如何创建查询集合类型,关系数据库类型,DataSet对象类型和XML类型的数据源的Linq查询表达式. 下面在实例代码ReadyCollectionData()函数创建了准备的数据 ...
- mysql数据库入门
在很多地方都有人提到MySQL这个数据,之前没有接触过的mysql数据库的童鞋们可以跟我一起走进mysql的世界. http://hovertree.com/menu/mysql/ 安装我就不多说了, ...
- 重新想象 Windows 8 Store Apps (55) - 绑定: MVVM 模式
[源码下载] 重新想象 Windows 8 Store Apps (55) - 绑定: MVVM 模式 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 绑定 通过 M ...
- 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传
[源码下载] 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 后台任务 后台 ...
- 重新想象 Windows 8.1 Store Apps (92) - 其他新特性: CoreDispatcher, 日历, 自定义锁屏系列图片
[源码下载] 重新想象 Windows 8.1 Store Apps (92) - 其他新特性: CoreDispatcher, 日历, 自定义锁屏系列图片 作者:webabcd 介绍重新想象 Win ...
- csharp: Flash Player play *.flv file in winform
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- wpf 查找页面的所有TextBox
private void EnumVisual(Visual myVisual) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount( ...
- android 6.0 httpclient
Apache HTTP Client RemovalAndroid 6.0 release removes support for the Apache HTTP client. If your ap ...
- 每个软件都自己把操作系统的host配置项加到内存中供频繁调用
nginx的转发,http_pass 转发到一个域名passport.ab.cn 那具体是到哪台机器上. 其实可以通过/etc/hosts文件来配置的. 可以理解,这个hosts文件是操作系统级别的, ...