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.pswp.cn/news/371538.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371538.shtml
英文地址,請注明出處:http://en.pswp.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)…