Java-Enum常量特定方法
admin
2024-02-03 11:45:47
0

OnJava8-Enum-常量特定方法

用枚举实现责任链模式

责任链(Chain Of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条“链”。

当一个请求先到达时,会顺着这条链传递下去,直到遇到链上某个可以处理该请求的方法。

可以很容易地用常量特定方法实现一条简单的责任链。考虑一个邮局模型,它对每一封邮件都会尝试用最常见的方式来处理,(如果行不通)并不断尝试别的方式,直到该邮件最终被视为“死信”(无法投递)。每种尝试可以看作一个策略(另一种设计模式),而整个策略列表放在一起就是一条责任链。

我们从一封邮件开始说起。它所有的重要特征都可以用来枚举表达。由于Mail对象是随机创建的,想要减小一封邮件的GenralDelivery被赋予YES的可能性,最简单的方法是创建更多的非YES的实例,因此枚举的定义一开始可能看起来有点好笑。

在Mail中,你会看到randomMail()方法,用来随机创建测试邮件。generator方法生成了一个Iterable对象,它使用randomMail方法来生成一定数量的Mail对象,每通过迭代器调用一次next()就会生成一个。这种结构允许通过调用Mail.genrator()方法实现for-in循环的简单创建能力。

首先对邮件进行建模:

package org.example.onjava.senior.example01enum.desgin;import org.example.onjava.onjavaUtils.Enums;import java.util.Iterator;/*** @Author Coder_Pans* @Date 2022/11/20 09:32* @PackageName:org.example.onjava.senior.example01enum.desgin* @ClassName: Mail* @Description: TODO 邮件建模* @Version 1.0*/
public class Mail {enum GeneralDelivery {YES,NO1,NO2,NO3,NO4,NO5}enum Scannability {UNSCANNABLE,YES1,YES2,YES3,YES4}enum Readability {ILLEGIBLE,YES1,YES2,YES3,YES4}enum Address {INCORRECT,OK1,OK2,OK3,OK4,OK5,OK6}enum ReturnAddress {MISSING,OK1,OK2,OK3,OK4,OK5}GeneralDelivery generalDelivery;Scannability scannability;Readability readability;Address address;ReturnAddress returnAddress;static long counter = 0;long id = counter++;@Override public String toString() {return "Mail " + id;}public String details() {return toString() +", General Delivery: " + generalDelivery +", Address Scannability: " + scannability +", Address Readability: " + readability +", Address Address: " + address +", Return address: " + returnAddress;}// Generate test Mail:public static Mail randomMail() {Mail m = new Mail();m.generalDelivery =Enums.random(GeneralDelivery.class);m.scannability =Enums.random(Scannability.class);m.readability =Enums.random(Readability.class);m.address = Enums.random(Address.class);m.returnAddress =Enums.random(ReturnAddress.class);return m;}public staticIterable generator(final int count) {return new Iterable() {int n = count;@Override public Iterator iterator() {return new Iterator() {@Override public boolean hasNext() {return n-- > 0;}@Override public Mail next() {return randomMail();}@Overridepublic void remove() { // Not implementedthrow new UnsupportedOperationException();}};}};}
}

创建常量特定方法:

package org.example.onjava.senior.example01enum.desgin;public class PostOffice {enum MailHandler {GENERAL_DELIVERY {@Override boolean handle(Mail m) {switch(m.generalDelivery) {case YES:System.out.println("Using general delivery for " + m);return true;default: return false;}}},MACHINE_SCAN {@Override boolean handle(Mail m) {switch(m.scannability) {case UNSCANNABLE: return false;default:switch(m.address) {case INCORRECT: return false;default:System.out.println("Delivering "+ m + " automatically");return true;}}}},VISUAL_INSPECTION {@Override boolean handle(Mail m) {switch(m.readability) {case ILLEGIBLE: return false;default:switch(m.address) {case INCORRECT: return false;default:System.out.println("Delivering " + m + " normally");return true;}}}},RETURN_TO_SENDER {@Override boolean handle(Mail m) {switch(m.returnAddress) {case MISSING: return false;default:System.out.println("Returning " + m + " to sender");return true;}}};abstract boolean handle(Mail m);}static void handle(Mail m) {for(MailHandler handler : MailHandler.values())if(handler.handle(m))return;System.out.println(m + " is a dead letter");}public static void main(String[] args) {for(Mail mail : Mail.generator(10)) {System.out.println(mail.details());handle(mail);System.out.println("*****");}}
}
/* Output:
Mail 0, General Delivery: NO2, Address Scannability:
UNSCANNABLE, Address Readability: YES3, Address
Address: OK1, Return address: OK1
Delivering Mail 0 normally
*****
Mail 1, General Delivery: NO5, Address Scannability:
YES3, Address Readability: ILLEGIBLE, Address Address:
OK5, Return address: OK1
Delivering Mail 1 automatically
*****
Mail 2, General Delivery: YES, Address Scannability:
YES3, Address Readability: YES1, Address Address: OK1,
Return address: OK5
Using general delivery for Mail 2
*****
Mail 3, General Delivery: NO4, Address Scannability:
YES3, Address Readability: YES1, Address Address:
INCORRECT, Return address: OK4
Returning Mail 3 to sender
*****
Mail 4, General Delivery: NO4, Address Scannability:
UNSCANNABLE, Address Readability: YES1, Address
Address: INCORRECT, Return address: OK2
Returning Mail 4 to sender
*****
Mail 5, General Delivery: NO3, Address Scannability:
YES1, Address Readability: ILLEGIBLE, Address Address:
OK4, Return address: OK2
Delivering Mail 5 automatically
*****
Mail 6, General Delivery: YES, Address Scannability:
YES4, Address Readability: ILLEGIBLE, Address Address:
OK4, Return address: OK4
Using general delivery for Mail 6
*****
Mail 7, General Delivery: YES, Address Scannability:
YES3, Address Readability: YES4, Address Address: OK2,
Return address: MISSING
Using general delivery for Mail 7
*****
Mail 8, General Delivery: NO3, Address Scannability:
YES1, Address Readability: YES3, Address Address:
INCORRECT, Return address: MISSING
Mail 8 is a dead letter
*****
Mail 9, General Delivery: NO1, Address Scannability:
UNSCANNABLE, Address Readability: YES2, Address
Address: OK1, Return address: OK4
Delivering Mail 9 normally
*****
*/

责任链模式的作用体现在了MailHandler枚举中,枚举的定义顺序则决定了各个策略在每封邮件上被应用的顺序。该模式会按顺序尝试应用每个策略,直到某个策略执行成功,或者全部策略都执行失败(即邮件无法投递)

用枚举实现状态机

枚举类型很适合用来实现状态机。状态机可以处于有限数量的特定状态。它们通常根据输入,从一个状态转移到下一个状态,但同时也会存在瞬态。当任务执行完毕后,状态机会立即跳出所有状态。

每个状态一般也会有某种对应的输出。

通过自动售货机案例来了解如何实现状态机,首先,在一个枚举中定义一系列输入:

/*** 用枚举实现状态机  01*/
public enum Input {NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100),TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50),ABORT_TRANSACTION {@Override public int amount() { // Disallowthrow new RuntimeException("ABORT.amount()");}},STOP { // This must be the last instance.@Override public int amount() { // Disallowthrow newRuntimeException("SHUT_DOWN.amount()");}};int value; // In centsInput(int value) { this.value = value; }Input() {}int amount() { return value; }; // In centsstatic Random rand = new Random(47);public static Input randomSelection() {// Don't include STOP:returnvalues()[rand.nextInt(values().length - 1)];}
}

VendingMachine(自动售货机)接收到输入后,首先通过Category(类别)枚举来对这些输入进行分类,这样就可以在各个类别间切换了。

package org.example.onjava.senior.example01enum.desgin;// enums/VendingMachine.java
// (c)2021 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// {java VendingMachine VendingMachineInput.txt}import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.function.Supplier;
import java.util.stream.Collectors;enum Category {MONEY(Input.NICKEL, Input.DIME,Input.QUARTER, Input.DOLLAR),ITEM_SELECTION(Input.TOOTHPASTE, Input.CHIPS,Input.SODA, Input.SOAP),QUIT_TRANSACTION(Input.ABORT_TRANSACTION),SHUT_DOWN(Input.STOP);private Input[] values;Category(Input... types) { values = types; }private static EnumMap categories =new EnumMap<>(Input.class);static {for(Category c : Category.class.getEnumConstants())for(Input type : c.values)categories.put(type, c);}public static Category categorize(Input input) {return categories.get(input);}
}public class VendingMachine {private static State state = State.RESTING;private static int amount = 0;private static Input selection = null;enum StateDuration { TRANSIENT } // Tagging enumenum State {RESTING {@Override void next(Input input) {switch(Category.categorize(input)) {case MONEY:amount += input.amount();state = ADDING_MONEY;break;case SHUT_DOWN:state = TERMINAL;default:}}},ADDING_MONEY {@Override void next(Input input) {switch(Category.categorize(input)) {case MONEY:amount += input.amount();break;case ITEM_SELECTION:selection = input;if(amount < selection.amount())System.out.println("Insufficient money for " + selection);else state = DISPENSING;break;case QUIT_TRANSACTION:state = GIVING_CHANGE;break;case SHUT_DOWN:state = TERMINAL;default:}}},DISPENSING(StateDuration.TRANSIENT) {@Override void next() {System.out.println("here is your " + selection);amount -= selection.amount();state = GIVING_CHANGE;}},GIVING_CHANGE(StateDuration.TRANSIENT) {@Override void next() {if(amount > 0) {System.out.println("Your change: " + amount);amount = 0;}state = RESTING;}},TERMINAL {@Overridevoid output() { System.out.println("Halted"); } };private boolean isTransient = false;State() {}State(StateDuration trans) { isTransient = true; }void next(Input input) {throw new RuntimeException("Only call " +"next(Input input) for non-transient states");}void next() {throw new RuntimeException("Only call next() for " +"StateDuration.TRANSIENT states");}void output() { System.out.println(amount); }}static void run(Supplier gen) {while(state != State.TERMINAL) {state.next(gen.get());while(state.isTransient)state.next();state.output();}}public static void main(String[] args) {Supplier gen = new RandomInputSupplier();if(args.length == 1)gen = new FileInputSupplier(args[0]);run(gen);}
}// For a basic sanity check:
class RandomInputSupplier implements Supplier {@Override public Input get() {return Input.randomSelection();}
}// Create Inputs from a file of ';'-separated strings:
class FileInputSupplier implements Supplier {private Iterator input;FileInputSupplier(String fileName) {try {input = Files.lines(Paths.get(fileName)).skip(1) // Skip the comment line.flatMap(s -> Arrays.stream(s.split(";"))).map(String::trim).collect(Collectors.toList()).iterator();} catch(IOException e) {throw new RuntimeException(e);}}@Override public Input get() {if(!input.hasNext())return null;return Enum.valueOf(Input.class, input.next().trim());}
}
/* Output:
25
50
75
here is your CHIPS
0
100
200
here is your TOOTHPASTE
0
25
35
Your change: 35
0
25
35
Insufficient money for SODA
35
60
70
75
Insufficient money for SODA
75
Your change: 75
0
Halted
*/

相关内容

热门资讯

欧冠早报:枪手拜仁直通+13队... 北京时间1月22日凌晨,2025-26赛季欧冠联赛阶段第7轮战罢,以下是今日的欧冠早报。 莱万乌龙+...
黄金、白银巨震!特朗普突然松口... 最新消息。 昨夜尾盘,黄金、白银走出深“V”行情。现货白银一度跳水跌超4.5%,之后快速拉升,截至收...
中行多家一级分行行长、副行长调... 来源:市场资讯 来源:金融人事mini 上周,银行人事分享了中行总行人事变动,本期主要介绍地方分行调...
原创 暴... 2026年1月22日,A股市场记录下一个关键日子:东通退(原东方通)的股票终止交易,正式从交易所摘牌...
宋清辉:市场过热,指数背离基本... 当前A股并非没有上涨空间,但上涨的质量和节奏,显然比点位本身更重要。在成交额逼近4万亿元、杠杆约束趋...
道县中医医院“一站式”血栓拦截... 大众卫生报·新湖南客户端1月16日讯(通讯员 唐海莲 曾玉麟)近日,永州市道县中医医院外二科在导管介...
原创 继... 文|毛巾 编|陈梅希 B站2025年百大UP主盛典如期而至。 无论是社交网站上用户猜百大名单的热情,...
问道2026——第一财经首席经... 来源:第一财经 第一财经邀请15位首席经济学家一起展望全年经济形势。 2025年经济运行成绩单刚刚...
腾讯淡马锡组团护航!湖南鸣鸣很... 湖南鸣鸣很忙商业连锁股份有限公司(简称“鸣鸣很忙”)于1月20日正式启动招股,招股期将持续至1月23...
上市公司花数百万美元给CEO买... 界面新闻记者 | 吕文琦 近期,两起金额高达数百万美元的要员保险安排,先后出现在港股上市公司的公告...
上海电气:预计2025年度净利... 每经AI快讯,上海电气1月21日晚间发布业绩预告,预计公司2025年度归属于母公司所有者的净利润为人...
今晚,油价下调! 据国家发展改革委消息,12月8日24时新一轮成品油调价窗口将开启。调价周期内,国际油价窄幅波动,平均...
货币政策加大宏观调控强度 为贯彻中央政治局会议精神,进一步实施好适度宽松的货币政策,中国人民银行行长潘功胜近日在国新办新闻发布...
国投白银LOF:将于1月22日... 国投瑞银白银期货证券投资基金(LOF)A类基金份额发布二级市场交易价格溢价风险提示及停复牌公告。近期...
2024年度个人所得税综合所得... 一、什么是年度汇算? 年度汇算指的是年度终了后,纳税人汇总一个纳税年度内取得的综合所得收入额,减除费...
原创 三... 2026年的春节脚步渐近,当电影市场摩拳擦掌争夺票房时,休闲零食赛道的“互联网鼻祖”三只松鼠却再次选...
通源环境大宗交易溢价成交3.8... 通源环境01月21日大宗交易平台共发生1笔成交,合计成交量3.88万股,成交金额202.46万元。成...
眼内手术自主机器人:重塑眼科手... 国中科院自动化研究所边桂彬团队研发的眼内手术自主机器人系统,正为眼科手术领域注入革命性力量,有望彻底...
从全球第四、全球第二,看中国汽... 近日,各大车企及行业媒体陆续发布了2024年汽车销量数据。在各类榜单中,比亚迪排名均十分优异:202...