下面是一个包装输入的类

package test;

import java.util.Random;

public enum Input {
NICKEL(5) , DIME(10) , QUARTER(25),DOLLAR(100),
TOOTHPASTE(200),CHIPS(75),SODA(100),SOAP(50),
ABOUT_TRANSACTION{
@Override
int amount() {
throw new RuntimeException("ABOUT_TRANSACTION") ;
}
} ,
STOP {
@Override
int amount() {
throw new RuntimeException("SHUT_DOWN.amount()") ;
}
} ; private int value ;
private Input(){}
private Input(int value ){
this.value = value ;
}
int amount(){
return value ;
}
/**
* 随机生成输入
*/
static Random random = new Random() ;
public static Input randomSelection(){
/**
* 产生 0 ~ values().length区间内的数 , 包括0 不包括values().length
*/
return values()[random.nextInt(values().length )] ;
}
public static void main(String[] args) {
for(int i = 0 ; i < 10 ; i ++){
System.out.println(Input.randomSelection());
}
}
}

在书中(第四版)values()[random.nextInt(values().length)]写错了,后面多减了一个1,

下面是主类,真不知道作者天天在想什么,竟然能想出这样的设计 --!

package test;
import static test.Input.ABOUT_TRANSACTION;
import static test.Input.CHIPS;
import static test.Input.DIME;
import static test.Input.DOLLAR;
import static test.Input.NICKEL;
import static test.Input.QUARTER;
import static test.Input.SOAP;
import static test.Input.SODA;
import static test.Input.STOP;
import static test.Input.TOOTHPASTE; import java.util.EnumMap;
/**
*
* 状态转换
*
* 模拟自动售货机的运行
*
*/ /**
* 该类是为了获得输入命令的类别
*/
enum Category{
MONEY(NICKEL,DIME,QUARTER,DOLLAR),
ITEM_SELECTION(TOOTHPASTE,CHIPS,SODA,SOAP),
QUIT_TRANSACTION(ABOUT_TRANSACTION),
SHUT_DOWN(STOP) ;
private Input[] values ;
private Category(Input... inputs ){
values = inputs ;
}
private static EnumMap<Input,Category> categories = new EnumMap<Input,Category>(Input.class) ; static {
for( Category c : Category.class.getEnumConstants()){
for( Input i : c.values){
categories.put(i, c) ;
}
}
}
public static Category getCategory(Input input ){
return categories.get(input) ;
}
}
public class VendingMachine {
/**
* 模拟状态之间的转换
*
*/
private static int amount = 0 ;
private static State state = State.RESTING ;
private static Input selection = null ;
enum StateDuration {TRANSIENT}
enum State {
RESTING {
void next(Input input ){
switch(Category.getCategory(input)){
case MONEY :
amount += input.amount() ;
state = ADDING_MONEY ;
break ;
case SHUT_DOWN:
state = TERMINAL ;
break ;
default :
}
}
},
ADDING_MONEY {
void next(Input input ){
switch(Category.getCategory(input)){
case MONEY :
amount += input.amount() ;
/**
* 这里为什么不要设置state的值?
* 因为当前已经是ADDING_MONEY状态,设置了以后还是这个状态,所以不需要设置
*/
break ;
case ITEM_SELECTION :
selection = input ;
if(amount < input.amount()){
System.out.println("Insufficient money for " + selection );
}else{
state = DISPENSING ;
}
break ;
case QUIT_TRANSACTION :
state = GIVING_CHANGE ;
break ;
case SHUT_DOWN :
state = TERMINAL ;
break ;
default :
}
}
},
DISPENSING(StateDuration.TRANSIENT){
void next(){
System.out.println("Here is your " + selection ) ;
amount -= selection.amount() ;
state = GIVING_CHANGE ;
}
},
GIVING_CHANGE(StateDuration.TRANSIENT){
void next(){
if(amount > 0 ){
System.out.println("you change : " + amount ) ;
amount = 0 ;
}
state = RESTING ;
}
},
TERMINAL {
void output(){
System.out.println("Halted!");
}
} ;
private boolean isTransaction = false ;
void next(){ }
void next(Input input ){
throw new RuntimeException("Only call next(Input input) for non-transient states ") ;
}
void output(){System.out.println(amount);}
State(){}
State(StateDuration trans ){
this.isTransaction = true ;
}
}
public static void run(Generator<Input> gen ){
/**
* 如果在前面执行的命令中是state变为terminal,则程序结束。
* 让其变为terminal的情况为输入的命令为STOP即SHUT_DOWN类别
*/
while(state != State.TERMINAL ){
/**
* 输入随机产生命令 , 当输入的命令非transaction类型的命令时,抛出异常 ,这在默认的next中设定
* 这里的state不可能是TERMINAL,也不可能是Transaction(因为下面那个while无限循环),
* 所以永远不会执行那个会抛出异常的next方法。
*/
state.next(gen.next()) ;
/**
* 判断该命令的剩下执行是否还需要命令,Transaction是true表示下面将要执行的任务不需要再输入命令
* 所以使用无限循环将该命令执行完,然后再输出余额
*/
while(state.isTransaction){
state.next() ;
}
state.output() ;
}
}
public static void main(String[] args) {
Generator<Input> gen = new RandomInputGenerator() ;
run(gen) ;
}
}
class RandomInputGenerator implements Generator<Input>{
@Override
public Input next() {
return Input.randomSelection() ;
}
}

java编程思想恶心的enum状态机示例的更多相关文章

  1. Java编程思想 (1~10)

    [注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第一章 对象导论 1.万物皆对象2.程序就是对象的集合3.每个对象都是由其它对象所构成 ...

  2. Java编程思想 第21章 并发

    这是在2013年的笔记整理.现在重新拿出来,放在网上,重新总结下. 两种基本的线程实现方式 以及中断 package thread; /** * * @author zjf * @create_tim ...

  3. 《Java编程思想》读书笔记(三)

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十一章到第十六章的内容,这一次 ...

  4. 《Java编程思想》读书笔记(四)

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...

  5. 《Java编程思想》读书笔记(五)

    前言:本文是<Java编程思想>读书笔记系列的最后一章,本章的内容很多,需要细读慢慢去理解,文中的示例最好在自己电脑上多运行几次,相关示例完整代码放在码云上了,码云地址:https://g ...

  6. JAVA编程思想(第四版)学习笔记----4.8 switch(知识点已更新)

    switch语句和if-else语句不同,switch语句可以有多个可能的执行路径.在第四版java编程思想介绍switch语句的语法格式时写到: switch (integral-selector) ...

  7. 《Java编程思想》读书笔记

    前言 这个月一直没更新,就是一直在读这本<Java编程思想>,这本书可以在Java业界被传神的一本书,无论谁谈起这本书都说好,不管这个人是否真的读过这本书,都说啊,这本书很好.然后再看这边 ...

  8. 《Java编程思想第四版完整中文高清版.pdf》-笔记

    D.2.1 安插自己的测试代码 插入下述“显式”计时代码,对程序进行评测: long start = System.currentTimeMillis(); // 要计时的运算代码放在这儿 long ...

  9. Java编程思想 4th 第2章 一切都是对象

    Java是基于C++的,但Java是一种更纯粹的面向对象程序设计语言,和C++不同的是,Java只支持面向对象编程,因此Java的编程风格也是纯OOP风格的,即一切都是类,所有事情通过类对象协作来完成 ...

随机推荐

  1. hdu1087 最大递增子段和

    http://acm.split.hdu.edu.cn/showproblem.php?pid=1087 状态方程:sum[j]=max{sum[i]}+a[j]; 其中,0<=i<=j, ...

  2. XSS 跨站脚本攻击之构造剖析(二)

    1.利用字符编码 (1)字符编码在跨站脚本中经常运用到,透过这种技巧,不仅能让XSS代码绕过服务端的过滤,还能更好的隐藏ShellCode (2)使用一个XSS编码工具,以便对字符串进行十进制和十六进 ...

  3. 20145223《Java程序设计》实验报告3

    20145223 实验三<敏捷开发与XP实践> 实验内容 使用git上传代码 使用git相互更改代码 实验步骤: 一.使用git上传代码 $ git push 1.找到需要push的文件所 ...

  4. HTML DOM Document

    Document 对象 每个载入浏览器的 HTML 文档都会成为 Document 对象. Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问. 提示:Document 对 ...

  5. ural 1075. Thread in a Space

    1075. Thread in a Space Time limit: 1.0 secondMemory limit: 64 MB There are three points in a 3-dime ...

  6. Java 动态代理

    被代理的接口特点: 1. 不能有重复的接口,以避免动态代理类代码生成时的编译错误. 2. 这些接口对于类装载器必须可见,否则类装载器将无法链接它们,将会导致类定义失败. 3. 需被代理的所有非 pub ...

  7. Node.js 手册查询-5-Ejs 方法

    express 中使用 //设置模板目录 app.set('views', path.join(__dirname, 'views')); //设置模板引擎 app.set('view engine' ...

  8. topcoder SRM 618 DIV2 MovingRooksDiv2

    一开始Y1,Y2两个参数看不懂,再看一遍题目后才知道,vector<int>索引代表是行数,值代表的是列 此题数据量不大,直接深度搜索即可 注意这里深度搜索的访问标识不是以前的索引和元素, ...

  9. Codeforces Round #242 (Div. 2) A. Squats

    注意题目一次只能改变一个松鼠,Pasha can make some hamster ether sit down or stand up.是单数不是复数 #include <iostream& ...

  10. Codeforces Round #233 (Div. 2) B. Red and Blue Balls

    #include <iostream> #include <string> using namespace std; int main(){ int n; cin >&g ...