Java枚举:您拥有优雅,优雅和力量,这就是我所爱!

当Java 8即将面世时,您确定您对Java 5中引入的枚举很了解吗? Java枚举仍然被低估了,很可惜,因为它们比您想象的要有用,它们不仅仅用于通常的枚举常量!

Java枚举是多态的

Java枚举是可以包含行为甚至数据的真实类。

让我们用一种方法用枚举来代表剪刀石头布游戏。 以下是定义行为的单元测试:

@Test
public void paper_beats_rock() {assertThat(PAPER.beats(ROCK)).isTrue();assertThat(ROCK.beats(PAPER)).isFalse();
}
@Test
public void scissors_beats_paper() {assertThat(SCISSORS.beats(PAPER)).isTrue();assertThat(PAPER.beats(SCISSORS)).isFalse();
}
@Test
public void rock_beats_scissors() {assertThat(ROCK.beats(SCISSORS)).isTrue();assertThat(SCISSORS.beats(ROCK)).isFalse();
}

这是枚举的实现,它主要依赖于每个枚举常量的序数整数,例如项N + 1胜过项N。在许多情况下,枚举常量和整数之间的等效关系非常方便。

/** Enums have behavior! */
public enum Gesture {ROCK() {// Enums are polymorphic, that's really handy!@Overridepublic boolean beats(Gesture other) {return other == SCISSORS;}},PAPER, SCISSORS;// we can implement with the integer representationpublic boolean beats(Gesture other) {return ordinal() - other.ordinal() == 1;}
}

注意,在任何地方都没有一个IF语句,所有业务逻辑都由整数逻辑和多态性处理,在这里我们将覆盖ROCK情况的方法。 如果项目之间的排序不是循环的,我们可以仅使用枚举的自然排序来实现,这里的多态性有助于处理循环。

您无需任何IF语句就可以做到! 是的你可以!

这个Java枚举也是一个完美的例子,您可以吃下蛋糕(提供带有意图公开名称的漂亮的面向对象的API),也可以吃下蛋糕(使用美好时光的简单而有效的整数逻辑实现)。

在我的上一个项目中,我使用了很多枚举来代替类:它们被保证为单例,具有顺序,哈希码,等值和序列化,并且都是内置的,而源代码中没有任何混乱。

如果您正在寻找Value Objects,并且可以用一组有限的实例代表域的一部分,那么枚举就是您所需要的! 它有点像Scala中的Sealed Case类 ,但是它完全限于在编译时定义的一组实例。 编译时实例的有限集合是一个真正的限制,但是现在有了连续交付功能 ,如果确实需要一种额外的情况,则可以等待下一个版本。  

非常适合策略模式

让我们进入一个(著名的) 欧洲歌唱大赛的系统 ; 我们希望能够配置何时向用户通知(或不通知)任何新的Eurovision事件的行为。 这一点很重要。 让我们用一个枚举来做到这一点:

/** The policy on how to notify the user of any Eurovision song contest event */
public enum EurovisionNotification {/** I love Eurovision, don't want to miss it, never! */ALWAYS() {@Overridepublic boolean mustNotify(String eventCity, String userCity) {return true;}},/*** I only want to know about Eurovision if it takes place in my city, so* that I can take holidays elsewhere at the same time*/ONLY_IF_IN_MY_CITY() {// a case of flyweight pattern since we pass all the extrinsi data as// arguments instead of storing them as member data@Overridepublic boolean mustNotify(String eventCity, String userCity) {return eventCity.equalsIgnoreCase(userCity);}},/** I don't care, I don't want to know */NEVER() {@Overridepublic boolean mustNotify(String eventCity, String userCity) {return false;}};// no default behaviorpublic abstract boolean mustNotify(String eventCity, String userCity);}

并针对非平凡案例进行单元测试:ONLY_IF_IN_MY_CITY:

@Test
public void notify_users_in_Baku_only() {assertThat(ONLY_IF_IN_MY_CITY.mustNotify("Baku", "BAKU")).isTrue();assertThat(ONLY_IF_IN_MY_CITY.mustNotify("Baku", Paris")).isFalse();
}

在这里,我们定义方法abstract ,仅在每种情况下都实现它。 一种替代方法是实现默认行为,并且仅在有意义的每种情况下才覆盖默认行为 ,就像在Rock-Paper-Scissors游戏中一样。

同样,我们不需要打开枚举来选择行为,而是依靠多态。 除了依赖关系之外,您可能不需要太多的枚举。 例如,当枚举是数据传递对象(DTO)中发送给外界的消息的一部分时,您不希望枚举或其签名中的内部代码具有任何依赖性。

对于欧洲电视网的策略,使用TDD我们可以从一个简单的布尔值开始(对于ALWAYS和NEVER)。 一旦我们引入第三个策略ONLY_IF_IN_MY_CITY,它将立即被提升为枚举。 提倡基元也是本着Object Calisthenics第七条规则“ 包装所有基元 ”的精神,而枚举是将布尔值或整数与一组可能的值进行包装的理想方法。

由于策略模式通常是由配置控制的,因此来往String的内置序列化也非常方便存储设置。  

完美匹配国家模式

就像策略模式一样,Java枚举非常适合于有限状态机 ,根据定义,可能状态的集合是有限的。

婴儿作为有限状态机(图片来自www.alongcamebaby.ca)

让我们以简化为状态机的婴儿为例,并使其成为枚举:

/*** The primary baby states (simplified)*/
public enum BabyState {POOP(null), SLEEP(POOP), EAT(SLEEP), CRY(EAT);private final BabyState next;private BabyState(BabyState next) {this.next = next;}public BabyState next(boolean discomfort) {if (discomfort) {return CRY;}return next == null ? EAT : next;}
}

当然,还有一些单元测试可以驱动行为:

@Test
public void eat_then_sleep_then_poop_and_repeat() {assertThat(EAT.next(NO_DISCOMFORT)).isEqualTo(SLEEP);assertThat(SLEEP.next(NO_DISCOMFORT)).isEqualTo(POOP);assertThat(POOP.next(NO_DISCOMFORT)).isEqualTo(EAT);
}@Test
public void if_discomfort_then_cry_then_eat() {assertThat(SLEEP.next(DISCOMFORT)).isEqualTo(CRY);assertThat(CRY.next(NO_DISCOMFORT)).isEqualTo(EAT);
}

是的,我们可以引用它们之间的枚举常量,但前提条件是只能引用以前定义的常量。 在这里,我们在状态EAT-> SLEEP-> POOP-> EAT等之间有一个循环。因此,我们需要打开循环并在运行时使用解决方法将其关闭。

我们确实有一个带有CRY状态的 ,可以从任何状态访问它。

我已经使用枚举通过简单地在每个节点中引用其元素(都带有枚举常量)来按类别表示简单 

枚举优化的集合

枚举还具有为其Map和Set专用实现实现的好处: EnumMapEnumSet

这些集合具有相同的接口,并且行为与常规集合类似,但是在内部,它们将枚举的整数性质用作优化。 简而言之,您将旧的C样式数据结构和习惯用法(位掩码等)隐藏在优雅的界面后面。 这也说明了您不必为了效率而妥协API!

为了说明这些专用集合的用法,让我们代表Jurgen Appelo的委派扑克中的7张牌:

public enum AuthorityLevel {/** make decision as the manager */TELL,/** convince people about decision */SELL,/** get input from team before decision */CONSULT,/** make decision together with team */AGREE,/** influence decision made by the team */ADVISE,/** ask feedback after decision by team */INQUIRE,/** no influence, let team work it out */DELEGATE;

一共有7张卡,前三张卡更加面向控制,中间的卡平衡,最后三张卡则更加面向委托(我已经解释清楚了,请参阅他的书进行解释)。 在“委托扑克”中,每个玩家都为给定情况选择一张牌,并赚取与该牌价值(从1到7)一样多的积分,“最高少数民族”的玩家除外。

使用顺序值+ 1计算点数很简单。通过顺序值选择面向控制的卡也很简单,或者我们可以像下面所做的那样使用从范围构建的Set来选择面向委托的牌:

public int numberOfPoints() {return ordinal() + 1;}// It's ok to use the internal ordinal integer for the implementationpublic boolean isControlOriented() {return ordinal() < AGREE.ordinal();}// EnumSet is a Set implementation that benefits from the integer-like// nature of the enumspublic static Set DELEGATION_LEVELS = EnumSet.range(ADVISE, DELEGATE);// enums are comparable hence the usual benefitspublic static AuthorityLevel highest(List levels) {return Collections.max(levels);}
}

EnumSet提供了方便的静态工厂方法,例如range(from,to),以创建一个集合,该集合包括在我们的示例中按声明顺序从ADVISE和DELEGATE开始的每个枚举常量。

为了计算最高的少数派,我们从最高的牌开始,除了找到最大值外,别无所求,因为枚举始终是可比的,所以这很琐碎。

每当我们需要将此枚举用作Map中的键时,都应使用EnumMap,如以下测试所示:

// Using an EnumMap to represent the votes by authority level
@Test
public void votes_with_a_clear_majority() {final Map<AuthorityLevel, Integer> votes = new EnumMap(AuthorityLevel.class);votes.put(SELL, 1);votes.put(ADVISE, 3);votes.put(INQUIRE, 2);assertThat(votes.get(ADVISE)).isEqualTo(3);
}

Java枚举很好,吃掉它们!

我喜欢Java枚举:它们在域驱动设计的意义上非常适合值对象,在此意义上限制了所有可能值的集合。 在最近的项目中,我特意设法将大多数值类型表示为枚举。 免费提供许多很棒的功能,尤其是几乎没有技术噪音的情况下。 这有助于提高我在域词和技术术语之间的信噪比

或者当然,我确保每个枚举常量也是不可变的 ,并且免费获取了正确的等于,哈希码,toString,String或整数序列化,单例性和非常有效的集合,所有这些都只需很少的代码即可。

(图片来自sys-con.com – Jim Barnabee文章)»]
多态的力量

枚举多态性非常方便,而且我从不对枚举使用instanceof ,也几乎不需要打开枚举。

我希望Java枚举由类似的构造完成,就像Scala中的case类一样,因为当可能的值集不能被限制时。 强制任何类保持不变的方法也很好。 我问得太多了吗?

同样,<troll>甚至都不要尝试将Java枚举与C#枚举进行比较... </ troll>

参考: Java枚举:您拥有优雅,优雅和力量,这就是我所爱! 从我们的JCG合作伙伴 Cyrille Martraire在Cyrille Martraire的博客博客中获得。


翻译自: https://www.javacodegeeks.com/2012/08/java-enums-you-have-grace-elegance-and.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#删除和清空文件夹的程序

/// <summary>/// 清空指定的文件夹&#xff0c;但不删除文件夹/// </summary>/// <param name"dir"></param>private void DeleteFolder(string dir){foreach (string d in Directory.GetFileSystemEntries(dir)){if (File.Exists(d)){try{…

2)网页请求顺序

&#xff08;1&#xff09;分析浏览器访问一个网页的完整流程逻辑过程&#xff1a;http&#xff1a;//www.abc.com/def/ 转载于:https://www.cnblogs.com/xiaoyoucai/p/7306246.html

JavaOne 2012:非阻塞数据结构如何工作?

当我查看今天的日程安排时&#xff0c;我感到有些惊讶&#xff0c;并指出我目前计划今天参加的所有会议都在希尔顿举行。 当我意识到JavaOne演示文稿中大约有一半是在希尔顿酒店中并且似乎按路线大致定位时&#xff0c;这变得有些不足为奇了。 Tobias Lindaaker &#xff08; 新…

c语言箭头指针的作用,C语言中,结构体成员变量的点和箭头

C语言中&#xff0c;调用成员变量用点还是用箭头&#xff0c;取决于当前的ID是指针还是结构体本身。如&#xff1a;typedef struct {float height;float weight;} Person;int main(int argc, char *argv[]) {Person jiushen;Person *lengleng (Person *)malloc(sizeof(Person)…

JavaOne 2012:调查JVM水晶球

我回到了希尔顿的A / B广场参加星期一的第四届会议&#xff0c;但首先去了希尔顿的顶层收拾午餐。 我每年都在JavaOne的第一天被提醒&#xff0c;涉及到每个人的第一天的午餐获取过程令人惊讶地令人沮丧。 我知道我在JavaOne的第一年的经历使我有些困惑&#xff0c;因为我不确定…

测试遇到的问题

多人合作测试 多人员合作测试&#xff0c;应尽量保证测试平台统一&#xff0c;处理流程统一&#xff0c;相互之间保持实时沟通。问题的处理进度应保证所负责的所有测试人员第一时间实时更新。 多人测试应做到2人或以上进行交叉测试。 转载于:https://www.cnblogs.com/liuliu-wo…

Jquery Memo

jQuery选择器 $( "#id" ) $( ".class" )$( "element" )全选择器&#xff08;*选择器&#xff09; * {padding: 0; margin: 0;}//子选择器 //$(div > p) 选择所有div元素里面的子元素P//后代选择器 //$(div p) 选择所有div元素…

c#语言输出字符串长度,C#统计字符长度(汉字占2个字符)

在C#编程过程中&#xff0c;通过String类的Length属性可以获取对应字符串的长度&#xff0c;但是细心的读者可能注意到了&#xff0c;String类的Length属性返回的是字符串中Char对象的个数&#xff0c;也就是说&#xff0c;一个汉字的长度为1&#xff0c;对此&#xff0c;MSDN的…

使用JMSTester对JMS层进行基准测试

对于我去过的大多数客户端&#xff0c;使用ActiveMQ扩展JMS消息传递层是一个优先事项。 有多种方法可以实现这一目标&#xff0c;但毫无疑问&#xff0c;创建基准测试并在实际硬件上分析架构&#xff08;或者正如我的同事Gary Tully所说的“询问机器”&#xff09;是第一步。 但…

Js引擎解析执行 阅读笔记

Js引擎解析执行 阅读笔记 一篇阅读笔记http://km.oa.com/group/2178/articles/show/145691?kmrefsearch&from_page1&no1 早期:遍历语法树 Js引擎最早使用的是遍历语法树方式 &#xff08;syntax tree walker&#xff09; 分为两步 词法分析语法分析词法分析 i a b *…

红外线遥控c语言程序,红外遥控的C程序

红外遥控在生产和生活中应用越来越广泛,不同的红外遥控芯片有不同的发码协议,但一般都是由引导码,系统码,键码三部分组成.引导码是告诉接收机准备接收红外遥控码.系统码是识别码,不同的遥控芯片有不同的误别码,以免搞错.遥控器上不同的按键有不同的键码,系统码和键码都是16位码…

Retrofit2 完全解析 探索与okhttp之间的关系

转载请标明出处&#xff1a; http://blog.csdn.net/lmj623565791/article/details/51304204&#xff1b; 本文出自:【张鸿洋的博客】 之前写了个okhttputils的工具类&#xff0c;然后有很多同学询问这个工具类和retrofit什么区别&#xff0c;于是上了下官网&#xff0c;发现其底…

不变性真的意味着线程安全吗?

我经常阅读有关“如果对象是不可变的&#xff0c;则它是线程安全的”的文章。 实际上&#xff0c;我从未找到过一篇让我相信不变的意味着线程安全的文章。 即使是Brian Goetz的Java Concurrency in Practice一书中关于不变性的一本书也没有完全令我满意。 在这本书中&#xff0…

c语言设计 数组的知识点,C语言程序设计知识点及示例.pdf

C语言程序设计知识点及示例四川大学锦江学院C语言程序设计知识点及示例知识点1&#xff1a;除了复合语句而外&#xff0c;C语言的语句都以分号结束。示例1&#xff1a;C语言的简单语句 (非复合语句语句)必须以 结束。参考答案&#xff1a;分号知识点2&#xff1a;目标程序和可执…

移动端知识汇总

参见地址: https://github.com/jtyjty99999/mobileTech 转载于:https://www.cnblogs.com/duanyue/p/7337789.html

在移动端设置overflow:hidden禁止滚动的解决方法

如果你是将overflow:hidden用在了body上那么不管用&#xff0c;因为移动端是基于touch事件。 两种解决方法&#xff1a; 1、为html和body同时设置height:100%;overflow:hidden; html, body{height:100%;overflow:hidden; }2、使用touchmove $(document).on(touchmove,function …

单元测试线程代码的5个技巧

这是一些技巧&#xff0c;说明如何进行代码的逻辑正确性测试&#xff08;与多线程正确性相对&#xff09;。 我发现本质上有两种带有线程代码的刻板印象模式&#xff1a; 面向任务–许多短期运行的同类任务&#xff0c;通常在Java 5执行程序框架内运行&#xff0c; 面向流程–…

jsp2

D:\Software\Tomcat7\work\Catalina\localhost 是缓存目录&#xff0c;可以删掉隐藏域&#xff1a;页面表单中的一个元素&#xff0c;跟文本框一样&#xff0c;但是用户看不到1.建立test1--form表单需要它&#xff0c;而不需要用户看到&#xff0c;用隐藏域<body><%re…

MongoDB MapReduce 的示例。

// JavaScript source code db.runCommand({mapreduce: "page",map: function Map() {emit(this.title, // how to group{ name: this.name } // associated data point (document));},reduce: function Reduce(key, values) {//reduce用来处理group出来是多条数…

c语言长空格的代码是什么,c语言中表示空格的是什么代码?

分析如下&#xff1a;不是所有字符都需要转义的&#xff0c;空格直接就敲空格&#xff0c;或者使用ASCII码值赋值为32。空格没有转义字符。合法转义字符如下&#xff1a;\a 响铃(BEL) 、\b 退格(BS)、\f 换页(FF)、\n 换行(LF)、\r 回车(CR)、\t 水平制表(HT)、\v 垂直制表(VT)…