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,一经查实,立即删除!

相关文章

2)网页请求顺序

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

JavaOne 2012:调查JVM水晶球

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

Jquery Memo

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

使用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语言中表示空格的是什么代码?

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

JavaOne 2012:101种改进Java的方法-开发人员参与为何如此重要

Bruno Souza &#xff0c; Martijn Verburg和Heather Vancura在希尔顿酒店的大陆宴会厅4中展示了“ 101种改进Java的方法&#xff1a;开发人员参与为何如此重要”。 他们将其分为自己最熟悉的领域。 SouJava的创始人兼协调员 Souza谈到了通过用户组的更大参与。 Verberg也在伦敦…

评论:Arun Gupta撰写的“ Java EE 6 Pocket Guide”

这是我很高兴写的评论。 我的朋友阿伦&#xff08;Arun&#xff09;发布了Java EE 6袖珍指南&#xff0c;该指南将在您订购时尽早提供。 我很早就知道这本书&#xff0c;因为我很乐意对其进行回顾&#xff0c;也感谢有机会为本书做出一点贡献&#xff01; Kindle版本已经可用&a…

双android手机同步工具,手机同步软件Android Manager使用图文教程

类型&#xff1a;手机工具大小&#xff1a;23.6M语言&#xff1a;繁体 评分&#xff1a;6.6标签&#xff1a;立即下载Android Manager 可透过五个简单的步骤设定&#xff1a;步骤一. 在计算机上安装 Android Manager请点选以下之下载按钮或直接于计算机上输入下载网址&#xff…

android拍照截图组件,Android截图命令screencap与视频录制命令screenrecord(示例代码)...

查看帮助命令[email protected] ~$ adb shell screencap -vscreencap: invalid option -- vusage: screencap [-hp] [-d display-id] [FILENAME]-h: this message-p: save the file as a png.-d: specify the display id to capture, default 0.If FILENAME ends with .png it …

Python-Matplotlib 18 注释

Python-Matplotlib 18 注释 EG1: import numpy as np import matplotlib.pyplot as plty np.arange(-5, 6,1) plt.plot(y, y*y) plt.annotate(Annotate , xy(0,1) , xytext(0,5) ,arrowpropsdict(facecolorr , frac0.2 ))plt.show()转载于:https://www.cnblogs.com/zsr0401/p/…

while和for循环

循环结构图&#xff1a; 循环结构主要分为两种&#xff1a;有while和for两种循环&#xff0c;while又分为do{...}while和while{...},do...while表示先执行后判断&#xff0c;而while循坏表示先判断后执行&#xff0c;如果循环条件都不满足的情况下&#xff0c;do...while至少执…

华为鸿蒙出来正当时,关于华为鸿蒙操作系统,中兴率先表态

原标题&#xff1a;关于华为鸿蒙操作系统&#xff0c;中兴率先表态 来源&#xff1a;科技数码迷进入2021年之后中兴这个品牌的存在感越来越强了&#xff0c;并且还学会了借势营销。每当国内智能手机领域有大事之时总会看到中兴或红魔手机的身影。这说明在5G过渡期中兴要借个机会…

条件变量(Condition Variable)详解

转载于&#xff1a;http://blog.csdn.net/erickhuang1989/article/details/8754357 条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法。举个简单的例子&#xff0c;应用程序A中包含两个线程t1和t2。t1需要在bool变量test_cond为true时才能…

android生成aar无效,android studio生成aar包并在其他工程引用aar包的方法

1.aar包是android studio下打包android工程中src、res、lib后生成的aar文件&#xff0c;aar包导入其他android studio 工程后&#xff0c;其他工程可以方便引用源码和资源文件2.生成aar包步骤&#xff1a;①.用android studio打开一个工程&#xff0c;然后新建一个Module&#…

圆周率的代码表示,以及对其的理解。

转载的简书&#xff0c;for 记录以及记忆。 http://www.jianshu.com/p/7208e4a58310 Thanks again&#xff01; 转载于:https://www.cnblogs.com/xiapeng0701/p/7538281.html

华为NOVa8Pr0是用鸿蒙系统吗,华为Nova8即将发布,采用麒麟芯片,高端平板适配鸿蒙系统...

大家好&#xff0c;我是老孙自从华为Mate40系列发布后&#xff0c;下一步新机动态备受外界关注&#xff0c;华为究竟会不会继续生产手机呢&#xff1f;答案是肯定&#xff0c;华为Nova8系列将于本月发布&#xff0c;华为P50系列也在积极筹备&#xff0c;而且都少不了麒麟芯片&a…

使用路标的Scala和Java的Twitter REST API

如果您已阅读此博客上的其他文章&#xff0c;您可能会知道我喜欢创建各种数据集的可视化。 我刚刚开始一个小项目&#xff0c;在这里我想可视化来自Twitter的一些数据。 为此&#xff0c;我想直接从Twitter检索有关关注者的信息和个人资料信息。 我实际上开始寻找一组所有推特帐…

大话设计模式读书笔记--11.抽象工厂模式

定义 抽象工厂模式定义: 提供一个创建一系列相关或相关依赖对象的接口,而无需指定他们具体的类 抽象工厂模式通常是用于创建一族产品&#xff0c;并且这族产品分不同的等级&#xff1b;不同的具体工厂类生产不同等级的一族产品 比如下图(来源于网络) 两厢车和三厢车称为两个不同…

Primefaces dataTable设置某个cell的样式问题

设置primefaces dataTable的源网段列的Cell可以编辑&#xff0c;当回车键保存时&#xff0c;判断是否输入的网段合法&#xff0c;如果不合法就显示警告信息&#xff0c;并将这个不合法的数据用红色表示。问题是&#xff0c;怎么给这一个cell设定样式。通过给标签设定ID然后在后…