Java-01enum常量特定方法
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 static
Iterable<Mail> generator(final int count) {
return new Iterable<Mail>() {
int n = count;
@Override public Iterator<Mail> iterator() {
return new Iterator<Mail>() {
@Override public boolean hasNext() {
return n-- > 0;
}
@Override public Mail next() {
return randomMail();
}
@Override
public void remove() { // Not implemented
throw 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() { // Disallow
throw new RuntimeException("ABORT.amount()");
}
},
STOP { // This must be the last instance.
@Override public int amount() { // Disallow
throw new
RuntimeException("SHUT_DOWN.amount()");
}
};
int value; // In cents
Input(int value) { this.value = value; }
Input() {}
int amount() { return value; }; // In cents
static Random rand = new Random(47);
public static Input randomSelection() {
// Don't include STOP:
return
values()[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<Input,Category> 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 enum
enum 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 {@Override
void 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<Input> gen) {
while(state != State.TERMINAL) {
state.next(gen.get());
while(state.isTransient)
state.next();
state.output();
}
}
public static void main(String[] args) {
Supplier<Input> gen = new RandomInputSupplier();
if(args.length == 1)
gen = new FileInputSupplier(args[0]);
run(gen);
}
}
// For a basic sanity check:
class RandomInputSupplier implements Supplier<Input> {
@Override public Input get() {
return Input.randomSelection();
}
}
// Create Inputs from a file of ';'-separated strings:
class FileInputSupplier implements Supplier<Input> {
private Iterator<String> 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
*/
Java-01enum常量特定方法的更多相关文章
- Java 静态变量,常量和方法
static 关键字 例如:在球类中使用PI这个常量,可能除了本类需要这个常量之外,在另外一个圆类中也需要使用这个常量.这时没有必要 在两个类中同时创建PI这个常量,因为这样系统会将这两个不在同一个类 ...
- Java parseInt_使用此方法得到的原始数据类型的一个特定的字符串
Java parseInt解释加方法示例 使用此方法得到的原始数据类型的一个特定的字符串. parseXxx()是一个静态方法,可以有一个参数或两个 java parseInt ...
- Java 字符串常量存放在堆内存还是JAVA方法区?
JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池. JDK1.8开始,取消了Java方法区,取而代之的是位于直接内 ...
- -1-1 java 基础语法 java关键字 java 注释 常量 语句 运算符 函数 数组定义
Java语言基础组成 关键字 标识符 注释 常量和变量 运算符 语句 函数 数组 关键字 定义:被Java语言赋予了特殊含义的单词 特点:关键字中所有字母都为小写 用于定义数据类型的关键字 class ...
- Java实现时间动态显示方法汇总
这篇文章主要介绍了Java实现时间动态显示方法汇总,很实用的功能,需要的朋友可以参考下 本文所述实例可以实现Java在界面上动态的显示时间.具体实现方法汇总如下: 1.方法一 用TimerTask: ...
- java String 中 intern方法的概念
1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...
- JAVA常见错误处理方法 和 JVM内存结构
OutOfMemoryError在开发过程中是司空见惯的,遇到这个错误,新手程序员都知道从两个方面入手来解决:一是排查程序是否有BUG导致内存泄漏:二是调整JVM启动参数增大内存.OutOfMemor ...
- 从几个sample来学习JAVA堆、方法区、JAVA栈和本地方法栈
最近在看<深入理解Java虚拟机>,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构: 感觉有 ...
- 转:JAVA常见错误处理方法 和 JVM内存结构
OutOfMemoryError在开发过程中是司空见惯的,遇到这个错误,新手程序员都知道从两个方面入手来解决:一是排查程序是否有BUG导致内存泄漏:二是调整JVM启动参数增大内存.OutOfMemor ...
- 如何在Java中避免equals方法的隐藏陷阱
摘要 本文描述重载equals方法的技术,这种技术即使是具现类的子类增加了字段也能保证equal语义的正确性. 在<Effective Java>的第8项中,Josh Bloch描述了当继 ...
随机推荐
- Jmeter进行服务器性能压力测试遇问题及解决方案
最近再给公司的一个项目进行服务器性能进行压测,要出一些报告图形展示,放弃了用boom工具我选择了用jmeter工具进行压测过程中遇到了一些问题下面将一一列出及解决方案希望帮助到你们!!! 1.装第三方 ...
- django文件目录
例如主站mysite,mysite下有一个应用testapp 1.在mysite/mysite下的settings需要添加应用进去 2.在musite/mysite下的urls.py记录应用的路径 3 ...
- 「SOL」旧试题 (LOJ/SDOI)
数论+图论,妙不可言 # 题面 给定 \(A,B,C\),求: \[\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\sigma_0(ijk) \] 数据规模:\(A,B,C\ ...
- python菜鸟学习: 7. 购物车升级版,用户、商品信息存储,修改,新增
# -*- coding: utf-8 -*-import os'''用户入口:1. 商品信息存在文件里2. 已购商品,余额记录商家入口1. 可以添加商品,修改商品价格商品信息:commdList.t ...
- 常用的js优秀框架个人记录
一.树框架 zTree http://www.treejs.cn/
- Linux 使用ssh服务管理远程主机
配置网络服务 配置网卡的4种方法: 创建网络会话 RHEL和CentOS系统默认使用NetworkManager来提供网络服务,这是一种动态管理网络配置的守护进程,能够让网络设备保持连接状态.可以使用 ...
- 24 Django模块的导入--常用总结
常用模块导入 1 forms # forms组件的使用 from django import forms 2 ValidationError # modelform报错时使用 from django. ...
- python实现学生信息管理系统——界面版
前言(写于2022年5月17日) 这篇博客是我两年前大二时写的,一直放在草稿箱里,还没写完,现在快毕业了,突然翻出来了.虽然博客没写完,但早就写好了代码,可运行的exe文件以及文档.现在上传到gite ...
- 给linux串口,增加登录密码
一.密码更改 1.在linux系统上,输入passwd,输入需要设定的密码,密码文件保存在/etc/passwd里面. 2.把/etc/passwd文件拷贝出来,放到rootfs的etc/目录下,实现 ...
- openSuse Tumbleweed 安装钉钉
办公软件钉钉提供了 Linux 版本,但是只有deb安装包. https://page.dingtalk.com/wow/z/dingtalk/default/dddownload-index ope ...