Java的枚举机制可以通过为每个枚举实例编写不同的方法,来赋予它们不同的行为。
package www.com.cat.chapter01;
import java.util.Arrays;
public enum ConstantSpecificMethod {
QU {
@Override
void action() {
System.out.println("生死喧嚣,归于寂静");
}
},
SUOLONG {
@Override
void action() {
System.out.println("三千世界");
}
};
abstract void action();
public static void main(String[] args) {
Arrays.stream(values()).forEach(ConstantSpecificMethod::action);
}
}
输出 :
生死喧嚣,归于寂静
三千世界
你可以通过关联的枚举实例来查找和调用方法,这通常叫做表驱动模式
。
枚举的各种实例可以拥有各自的行为,这表明每个实例都是不同的类型。
package www.com.cat.chapter01;
import java.util.EnumMap;
import java.util.EnumSet;
public class People {
enum Ninja{
YOU {
@Override
void action() {
System.out.println("月读");
}
},
DAITU {
@Override
void action() {
System.out.println("神威");
}
},
KAKAXI {
@Override
void action() {
System.out.println("雷切");
}
},
MINGREN {
@Override
void action() {
System.out.println("螺旋丸");
}
};
abstract void action();
}
EnumSet<Ninja> ninjas = EnumSet.noneOf(Ninja.class);
public void add(Ninja ninja) {
ninjas.add(ninja);
}
public void ninjasAction() {
ninjas.stream().forEach(Ninja::action);
}
@Override
public String toString() {
return ninjas.toString();
}
public static void main(String[] args) {
People people = new People();
System.out.println(people);
people.add(Ninja.DAITU);
people.ninjasAction();
people.add(Ninja.MINGREN);
people.add(Ninja.KAKAXI);
people.add(Ninja.YOU);
people.add(Ninja.DAITU);
System.out.println(people);
people.ninjasAction();
}
}
输出 :
[]
神威
[YOU, DAITU, KAKAXI, MINGREN]
月读
神威
雷切
螺旋丸
添加枚举实例的顺序并不重要–输出顺序由枚举声明的顺序决定。
1.10.1 用枚举实现职责链模式
职责链(Chain of Responsibility)
设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条"链"。当一个请求到达时,就会顺着这条链传递下去,直到链上某个可以处理该请求的方法。
这么长的代码写得我心儿都碎了。
package www.com.cat.chapter01;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@SuppressWarnings("all")
class Mail {
enum Hero {
QU, LUXIYA, LUNA, HANYING, QISHI, LUOSAITA;
}
enum JoJo {
KIllERQUEEN, STARPLATINUM, THEWORLD, GOLDEXPERIENCE, HEAVENSDOOR;
}
enum Ninja {
ZUOZHU, MINGREN, ZILAIYE, WOAILUO, BAN, KAI;
}
enum HaiZei {
SUOLONG, LUFEI, SHANZHI, MIHUOKE, BAJI;
}
enum BuLiangRen {
LIXINYUN, JIRUXUE, CHIMENG, YUANTIANGANG, LIMANGZHEN;
}
Hero hero;
JoJo jojo;
Ninja ninja;
HaiZei haizei;
BuLiangRen buliangren;
static long counter = 0;
long id = counter++;
@Override
public String toString() {
return "Mail" + id;
}
public String details() {
return "Hero : " + hero + ", jojo : " + jojo + ", ninja : " + ninja + ", haizei : " + haizei + ", buliangren : " + buliangren;
}
// 生成测试邮件
public static Mail randomMail() {
Mail mail = new Mail();
mail.hero = Enums.random(Hero.class);
mail.jojo = Enums.random(JoJo.class);
mail.ninja = Enums.random(Ninja.class);
mail.haizei = Enums.random(HaiZei.class);
mail.buliangren = Enums.random(BuLiangRen.class);
return mail;
}
public static Iterable<Mail> generator(final int count) {
return new Iterable<Mail>() {
int total = count;
@Override
public Iterator<Mail> iterator() {
return new Iterator<Mail>() {
@Override
public boolean hasNext() {
return total-- > 0;
}
// 生成一个随机的护送列表
@Override
public Mail next() {
return randomMail();
}
};
}
};
}
}
@SuppressWarnings("all")
public class Delivery {
enum MailHandler {
HeroHan {
@Override
boolean check(Mail mail) {
switch (mail.hero) {
case QU:
case LUNA:
case HANYING:
case QISHI:
return true;
default:
System.out.println("Error : " + mail.hero);
return false;
}
}
},
JoJoHan {
@Override
boolean check(Mail mail) {
switch (mail.jojo) {
case STARPLATINUM:
case KIllERQUEEN:
case GOLDEXPERIENCE:
case THEWORLD:
return true;
default:
System.out.println("Error : " + mail.jojo);
return false;
}
}
},
NinjaHan {
@Override
boolean check(Mail mail) {
switch (mail.ninja) {
case ZUOZHU:
case MINGREN:
case BAN:
case KAI:
return true;
default:
System.out.println("Error : " + mail.ninja);
return false;
}
}
},
HaiZeiHan {
@Override
boolean check(Mail mail) {
switch (mail.haizei) {
case SUOLONG:
case LUFEI:
case SHANZHI:
case MIHUOKE:
return true;
default:
System.out.println("Error : " + mail.haizei);
return false;
}
}
},
BuLiangRenHan {
@Override
boolean check(Mail mail) {
switch (mail.buliangren) {
case LIXINYUN:
case JIRUXUE:
case YUANTIANGANG:
case LIMANGZHEN:
return true;
default:
System.out.println("Error : " + mail.buliangren);
return false;
}
}
};
abstract boolean check(Mail mail);
}
public static void handle(Mail mail) {
for (MailHandler handler : MailHandler.values()) {
if (!handler.check(mail)) {
return;
}
}
System.out.println("Successful!!!");
}
public static void main(String[] args) {
for (Mail mail : Mail.generator(10)) {
System.out.println(mail.details());
handle(mail);
System.out.println("*******************************");
}
}
}
输出 :
Hero : QU, jojo : KIllERQUEEN, ninja : ZUOZHU, haizei : SHANZHI, buliangren : JIRUXUE
Successful!!!
*******************************
Hero : LUOSAITA, jojo : KIllERQUEEN, ninja : KAI, haizei : SUOLONG, buliangren : LIXINYUN
Error : LUOSAITA
*******************************
Hero : LUOSAITA, jojo : HEAVENSDOOR, ninja : WOAILUO, haizei : SUOLONG, buliangren : YUANTIANGANG
Error : LUOSAITA
*******************************
Hero : QU, jojo : GOLDEXPERIENCE, ninja : BAN, haizei : BAJI, buliangren : LIMANGZHEN
Error : BAJI
*******************************
Hero : HANYING, jojo : GOLDEXPERIENCE, ninja : KAI, haizei : BAJI, buliangren : YUANTIANGANG
Error : BAJI
*******************************
Hero : LUNA, jojo : HEAVENSDOOR, ninja : ZUOZHU, haizei : LUFEI, buliangren : CHIMENG
Error : HEAVENSDOOR
*******************************
Hero : HANYING, jojo : GOLDEXPERIENCE, ninja : BAN, haizei : SHANZHI, buliangren : JIRUXUE
Successful!!!
*******************************
Hero : LUOSAITA, jojo : STARPLATINUM, ninja : WOAILUO, haizei : SUOLONG, buliangren : CHIMENG
Error : LUOSAITA
*******************************
Hero : QU, jojo : GOLDEXPERIENCE, ninja : ZILAIYE, haizei : SHANZHI, buliangren : JIRUXUE
Error : ZILAIYE
*******************************
Hero : LUNA, jojo : HEAVENSDOOR, ninja : ZILAIYE, haizei : SHANZHI, buliangren : LIMANGZHEN
Error : HEAVENSDOOR
*******************************
其实我写的程序功能比书上稍微强大一点,我的程序会打印出在职责链上是谁没有成功完成任务
职责链模式
的作用体现在了MainHandler
枚举中,枚举的定义顺序则决定了各个策略在每封邮件上被应用的顺序。该模式会按顺序尝试应用每个策略,直到某个策略执行成功,或者全部策略都执行失败。
1.10.2 用枚举实现状态机
枚举类型很适合用来实现状态机
。状态机可以处于有限数量的特定状态。它们通常根据输入,从一个状态移动到下一个状态,但同时也会存在瞬态。当任务执行完毕后,状态机会立即跳出所有状态
个人认为这本书最大的缺点就是示例代码给的太长,也太难了。没有基础的话看这么长这么难的代码,看得心都碎了,就算有基础的话,看起来也很累。
package www.com.cat.chapter01;
import java.util.Random;
public enum Input {
NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100), TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50),
ABORT_TRANSACTION {
@Override
int amount() {
throw new RuntimeException("ABORT_TRANSACTION.amount()");
}
},
STOP {
@Override
int amount() {
throw new RuntimeException("STOP.amount()");
}
};
int value;
Input(int value) {
this.value = value;
}
Input() {
}
int amount() {
return value;
}
static Random random = new Random(13);
public static Input randomSelection() {
// 不存在stop
return values()[random.nextInt(values().length - 1)];
}
}
下面是一个自动售卖机的例子
我的代码很长,你忍一下
package www.com.cat.chapter01;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
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;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@SuppressWarnings("all")
// 为原来能对自动售卖机的操作分类
// 使用了Category来达到分类的目的
enum Category {
// 收钱
MONEY(Input.DIME, Input.DOLLAR, Input.NICKEL, Input.QUARTER),
// 能购买的物品
ITEM(Input.TOOTHPASTE, Input.SODA, Input.SOAP, Input.CHIPS),
// 退出
QUIT(Input.ABORT_TRANSACTION),
SHUTDOWN(Input.STOP);
Input[] inputs;
Category(Input... inputs) {
this.inputs = inputs;
}
private static EnumMap<Input, Category> categories = new EnumMap<>(Input.class);
static {
// for (Category category : Category.class.getEnumConstants()) {
// for (Input input : category.inputs) {
// categories.put(input, category);
// }
// }
// 下面的流操作与上面的for循环功能一致
Arrays.stream(Category.class.getEnumConstants()).
forEach(category -> Arrays.stream(category.inputs).
forEach(input -> categories.put(input, category)));
System.out.println(categories);
}
// 得到这个input的操作类型
public static Category categorize(Input input) {
return categories.get(input);
}
}
@SuppressWarnings("all")
// 下面这两个类都是用来输入指令的,这个使用文件来输入指令
class FileInputSupplier implements Supplier<Input> {
private Iterator<String> input;
public FileInputSupplier(String filename) {
try {
// 文件会以特定的格式存在
input = Files.lines(Paths.get(filename)).skip(1). // 跳过注释行
flatMap(s -> Arrays.stream(s.split(";"))). // 得到一行的内容,这行有多个指令以;分隔,首先将行以;切割,这会得到多个流,再将流合并
map(String::trim).collect(Collectors.toList()).iterator(); // 去除空格和换行,将每一行的内容都收集到一个List中,再将这个List的迭代器返回。
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 获得一个指令
@Override
public Input get() {
// 没有指令就返回null
if (!input.hasNext()) {
return null;
}
String next = input.next().trim().replace('-', '_');
// 返回一个指令,因为指令是一字符串的形式存在的,所以将其转换成Input类型
return Enum.valueOf(Input.class, next);
}
}
class RandomInputSupplier implements Supplier<Input> {
@Override
public Input get() {
// 随机获得一个指令
return Input.randomSelection();
}
}
@SuppressWarnings("all")
// 自动售卖机类
public class VendingMachine {
private static State state = State.RESTING;
// amount : 记录客户投进自动售卖机的钱
private static int amount = 0;
// 将要执行的指令
private static Input selection = null;
// 是否为瞬态
enum StateDuration {
TRANSIENT;
}
enum State {
// 初始态,此时直接接受投币和退出操作
RESTING {
@Override
void next(Input input) {
switch (Category.categorize(input)) {
case MONEY: // 投币后状态转为ADDING_MONEY
amount += input.amount();
state = ADDING_MONEY;
break;
case SHUTDOWN:
state = TERMINAL;
default: // 其他类型指令不响应
}
}
},
// 已投币态
ADDING_MONEY {
@Override
void next(Input input) {
// 取出是哪一种状态,究竟是买东西还是给钱还是终止操作
switch (Category.categorize(input)) {
case MONEY: // 一次可以投多枚硬币,所以状态不用变仍然保持ADDING_MONEY就好
amount += input.amount();
break;
case ITEM: // 选择物品
selection = input; // 买东西,selection指向被选中的物品
if (amount < selection.amount()) { // 投进去的钱不够,此时还需要投更多的钱,故状态仍然保持不变
System.out.println("Insufficient money for " + selection);
} else {
state = DISPENSING; // 把东西给顾客
}
break;
case QUIT: // 不买了
state = GIVING_CHANGE; // 把剩余的钱还给顾客
break;
case SHUTDOWN: // 关闭
state = TERMINAL;
default: // 其余的指令不响应
}
}
},
// 交货态
DISPENSING(StateDuration.TRANSIENT) {
@Override
void next() {
System.out.println("Here is your " + selection); // 把货物给顾客
amount -= selection.amount(); // 还剩下多少钱,在进入这个状态之前就已经确认过钱够不够了(见ADDING_MONEY)
// state = GIVING_CHANGE; // 其实这里不用着急吐钱出来,这样一次就只能买一个物品,显得机器很蠢
state = ADDING_MONEY; // 应该再次回到已投币态,在那里选择退出,或接着投币买更多东西
}
},
// 找零态
GIVING_CHANGE(StateDuration.TRANSIENT) {
@Override
void next() {
if (amount > 0) {
System.out.println("Your change : " + amount); // 把剩下的钱全部交给顾客
amount = 0; // 将钱清零
}
state = RESTING; // 回到初始状态
}
},
TERMINAL { // 终止态
@Override
void output() {
System.out.println("Halted");
}
};
private boolean isTransient = false;
State() {
}
State(StateDuration trans) {
isTransient = true;
}
// 如果是枚举实例没有重写这这两个方法就直接抛出异常
void next(Input input) {
System.out.println(state);
throw new RuntimeException("Only call" + "next(Input input) for non-transient state");
}
void next() {
throw new RuntimeException("Only call " + "next() for StateDuration.TRANSIENT states");
}
void output() {
System.out.println(amount);
}
}
static void run(Supplier<Input> supplier) {
while (state != State.TERMINAL) { // 不是终止态就一直运行
state.next(supplier.get()); // state一开始是初始态,此时它从supplier获取一个指令
while (state.isTransient) { // 进入这个状态之后,它不会保持在这个状态
state.next();
}
state.output(); // 打印出当前状态下有多少钱
}
}
public static void main(String[] args) {
Supplier<Input> supplier = new RandomInputSupplier();
if (args.length == 1) {
supplier = new FileInputSupplier(args[0]);
}
run(supplier);
// IntStream.rangeClosed(1, 20).forEach(x -> System.out.println(supplier.get()));
}
}
输出 :
{NICKEL=MONEY, DIME=MONEY, QUARTER=MONEY, DOLLAR=MONEY, TOOTHPASTE=ITEM, CHIPS=ITEM, SODA=ITEM, SOAP=ITEM, ABORT_TRANSACTION=QUIT, STOP=SHUTDOWN}
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
输入文件 :
// 为了与书上保持一致写的
QUARTER;QUARTER;QUARTER;CHIPS;
DOLLAR;DOLLAR;TOOTHPASTE;
QUARTER;DIME;ABORT-TRANSACTION;
QUARTER;DIME;SODA;
QUARTER;DIME;NICKEL;SODA;
ABORT-TRANSACTION;
STOP;
标签:case,return,常量,1.10,特定,mail,Override,Input,public
From: https://blog.csdn.net/StarPlatinum2/article/details/144825338