java枚举最佳实践
2017-04-16 16:26
211 查看
背景
场景是这样的,客户端要发送JSON数据到达服务端解析,由于客户端的不同版本更新,打过来的数据有差异,服务端要兼容这种差异对不同的处理这些数据,因为客户端升级是由用户决定的。思路
实现的方式肯定很多种,恰好学到《effective java》中的枚举,枚举可以加一个方法,我们这个场景每一种日志格式就对应于一种解析的方法。public enum LogVersion { OLD(0),NEW(1){ @Override public String parseLog(JSONObject jsonObject) { return jsonObject.toString() + "new"; } }; private final int num; private LogVersion(int num) { this.num = num; } public String parseLog(JSONObject jsonObject) { return jsonObject.toString(); } public static void main(String[] args) { JSONObject jsonObject = new JSONObject(); String oldVersionLog = OLD.parseLog(jsonObject); String newVersionLog = NEW.parseLog(jsonObject); System.out.println(oldVersionLog); System.out.printf(newVersionLog); } }
当然,项目中实现的逻辑比这个复杂得多。但是,这样做就好吗?极致的代码都在追求:扩展性、复用性、性能。如果客户端再发一个版本,我们在里面重写解析方法就好;当很多不同类型的客户端觉得这个处理逻辑很相似,需要复用这个
LogVersion的处理,这样就会带来问题,首先是命名我们命得不好,另外是把不同的客户端日志放在同一个
Enum中处理并不是那么的优雅,而且逻辑上我们本来就应该想办法把他分开。如何来扩展这个
Enum?
enum是什么?
enum就是一个类,只不过这个类编译器额外的帮我们做了一些事情:
enum会自动继承Enum这个类;由于java不支持多继承,这个类被声明成enum就不能再继承其他类了,所以这就是enum 不能用继承来扩展的原因。
enum类,编译器会偷偷的在前面加
public static final。
enum类的构造方法只能是
private或者
default的。
如何扩展enum
根据1.0中的第一点,我们只能用接口来扩展,以达到代码逻辑结构清晰的目的。public enum BasicLogVersion implements LogVersion { OLD(0),NEW(1){ @Override public String parseLog(JSONObject jsonObject) { return jsonObject.toString() + "new"; } }; private final int num; private BasicLogVersion(int num) { this.num = num; } public String parseLog(JSONObject jsonObject) { return jsonObject.toString(); } }
public enum AdvancedLogVersion implements LogVersion{ ADVANCED_LOG_VERSION1 { @Override public String parseLog(JSONObject jsonObject) { return super.parseLog(jsonObject) + "ADVANCED_LOG_VERSION1"; } }, ADVANCED_LOG_VERSION2 { @Override public String parseLog(JSONObject jsonObject) { return super.parseLog(jsonObject) + "ADVANCED_LOG_VERSION2"; } }; @Override public String parseLog(JSONObject jsonObject) { return null; } }
这样继承同一个接口,就把两类enum,但是有相同的结构联系到了一起,解决了我们把所有enum放在一起不合适,但是完全创建一个新的enum又感觉不好的尴尬境地。
不要使用ordinal方法
不要使用ordinal来标识顺序
这个方法的使用会使得你对一个enum加入新的元素依赖于原有的顺序,所以尽量给enum的构造加上一个数字和字符串。public enum Log { Version1, Version2; public int versionOfLog() { return ordinal()+1; } }
这样写你如果是顺序加入还好,但是在大型系统中,而且经常用git merge来merge去的。很多人会把enum放到自己相关的业务位置,这样读起来方便,如果你这时候依赖ordinal方法就会是灾难。
正确的做法是:
public enum Log { Version1(1), Version2(2); private int order; Log(int order) { this.order = order; } public int versionOfLog() { return this.order; } }
不要使用ordinal来查询map
用一个enum去查对应的东西,太常见不过了,但是绝对不要用ordinal去查,因为谁也无法预知变化。那如何避免呢?用EnumMap。假设目前的场景我们只有两种log需要进一步处理,而且处理的方式不相同,你可能会说把它放到enum中Override这个方法就好,但是一方面,业务逻辑可能会比较复杂,第二是我们可能只需要处理一部分,另外的一部分不需要处理。
public class LogProcess1 implements LogProcessable{ public enum AdvancedLogVersion implements LogVersion { ADVANCED_LOG_VERSION1 { @Override public String parseLog(JSONObject jsonObject) { return super.parseLog(jsonObject) + "ADVANCED_LOG_VERSION1"; } }, ADVANCED_LOG_VERSION2 { @Override public String parseLog(JSONObject jsonObject) { return super.parseLog(jsonObject) + "ADVANCED_LOG_VERSION2"; } }, ADVANCED_LOG_VERSION3 { @Override public String parseLog(JSONObject jsonObject) { return super.parseLog(jsonObject) + "ADVANCED_LOG_VERSION3"; } }, ADVANCED_LOG_VERSION4 { @Override public String parseLog(JSONObject jsonObject) { return super.parseLog(jsonObject) + "ADVANCED_LOG_VERSION4"; } }; @Override public String parseLog(JSONObject jsonObject) { return null; } } public static void main(String[] args) { Map<AdvancedLogVersion, LogProcessable> logVersionLogProcessMap = new EnumMap<AdvancedLogVersion, LogProcessable>(AdvancedLogVersion.class); logVersionLogProcessMap.put(AdvancedLogVersion.ADVANCED_LOG_VERSION1, new LogProcess1()); logVersionLogProcessMap.put(AdvancedLogVersion.ADVANCED_LOG_VERSION2, new LogProcess2()); } }
目前来说,我遇到的场景这些是够用的了,至于effective java中说到的其他enum技巧,我目前还没使用。
reference
Java 枚举型为什么是静态的,以及是怎么实现的?相关文章推荐
- Java面向对象设计最佳实践 - 枚举设计
- java:log4j学习(3)-转帖:Log4J 最佳实践之全能配置文件
- Spring 总结XML配置的十二个最佳实践-Java基础-Java-编程开发
- Yale CAS最佳实践 --全部 (转http://www.javaeye.com/wiki/SSO/535-Yale%20CAS最佳实践%20--全部)
- Java最佳实践
- Java Exception处理之最佳实践
- [原创]Java最佳实践笔记。(不断更新)
- chap 20:使用 Java Native Interface 的最佳实践
- 使用 Java Native Interface 的最佳实践
- [Java] Appfuse 最佳实践
- JAVA12个最重要的J2EE最佳实践
- Java Exception 处理之最佳实践
- [Java] Appfuse 最佳实践
- java面向对象设计最佳实践 专题 与 Java程序员应该掌握的10项技能
- Java面向对象设计最佳实践 - 内置类设计 3
- 若干条J2EE应用中运用“配置”的最佳实践 - 企业应用 - Java - JavaEye论坛
- 轻量级单点登录系统最佳实践(十一)——5.6.网上办公系统演示App3 (Java)
- 使用 Java Native Interface 的最佳实践
- Java面向对象设计最佳实践――内置类设计
- chap 20:使用 Java Native Interface 的最佳实践