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
*/

相关内容

热门资讯

青海:“五一”假期推出60余场... 中新网西宁5月6日电 (潘雨洁)记者6日从青海省商务厅获悉,“五一”假期,青海省各级商务部门、金融机...
银行业竞争逻辑正在经历一场变革 证券时报记者 马传茂 步入低利率时代,银行业关于“规模情结”的讨论持续发酵。一个耐人寻味的现象是:银...
基本面与新技术共振,锂电新周期... 5月国内电池排产达172.4GWh,环比增8%,同比猛增65%。另一边,钠电逻辑迎来里程碑:宁德时代...
曾是OpenAI前董事会成员!... 快科技5月7日消息,据媒体报道,日前,马斯克起诉了他的两位OpenAI联合创始人——CEO萨姆·奥特...
监护仪警报后,我们在做什么 杨明明 河北医科大学第一医院 在医院的病房、急诊室和ICU,监护仪的“滴滴”警报声是最常见的声音。很...
原创 美... 美股三大指数昨晚(当地时间5月5日)集体收涨,标普500和纳斯达克双双再创历史新高。 最惊人的一幕发...
华泰证券:地产板块估值筑底、配... 华泰证券研报指出,深圳、广州、武汉、苏州、济南等核心城市相继出台楼市优化政策,从公积金放宽、以旧换新...
第四批全国中成药联盟采购开标 ... 4月30日,第四批全国中成药联盟采购(以下简称“全国联采”)在武汉开标产生拟中选结果。本次集采纳入2...
跟踪800自由现金流的ETF有... 随着A股市场从估值修复转向盈利驱动,投资者对企业"真金白银"创造能力的关注度显著提升。自由现金流策略...
金价强势反弹,投资者怎么操作? 经历持续阴跌后,黄金市场迎来一轮强势反弹行情。 5月6日,国际金价短暂震荡后强势拉升。截至记者发稿,...
A股5月“开门红” 两市成交额... 科创50日K线图   张大伟 制图 ◎记者 费天元 5月首个交易日,A股主要股指全线上攻,盘面热点延...
首发|又一个核聚变独角兽:星环... 投资界获悉,星环聚能完成5亿元人民币A+轮融资,投资方阵容依旧豪华:包括达晨财智、金浦投资、上海申能...
为何翻倍提高CPU市场展望?苏... 财联社5月7日讯(编辑 史正丞)随着超威半导体(AMD)的最新财报再度唤起市场对CPU需求周期的关注...
“1页纸”让欧美亚股市大涨,油... 新华社援引美国媒体5月6日报称道,两名美国官员及另外两名知情人士透露,白宫认为,与伊朗接近达成一份一...
拟上市企业股权激励的注意事项 在企业的发展进程中,拟上市企业的股权激励是一个至关重要的环节。它不仅能够吸引和留住核心人才,还能激发...
5月7日每日研选丨基本面与新技... 5月国内电池排产达172.4GWh,环比增8%,同比猛增65%。另一边,钠电逻辑迎来里程碑:宁德时代...
美股收盘:纳指、标普再创新高 ... 财联社5月7日讯(编辑 史正丞)昨夜今晨,随着AI相关资产接力暴涨,标普500指数和纳斯达克指数连续...
美联储古尔斯比就通胀与消费者行... 芝加哥联邦储备银行行长奥斯滕・古尔斯比对通胀形势发出谨慎警示:美国通胀不仅未能持续回落至美联储 2%...
原创 北... 实验室里长出的,不只是论文还有独角兽。 又是一年五四,北大迎来了128岁生日。 未名湖畔的故事讲了...