枚举类型非常适合用来创建状态机,一个状态机通常可以拥有有限的几个状态,他通常根据输入,从一个状态进入到下一个状态。
下面是一个用枚举实现的自动售货机的例子,很简陋,但是表达清楚了意思就差不多了,也希望各位看官能指出不足之处。
- package enums;
- import java.util.Random;
- /**
- * @描述 售货机可以接收的钞票金额和所有商品的价格
- * @创建时间 2012-5-27
- * @另请参照
- */
- public enum Input {
- /**五分硬币**/
- NICKEL(5),
- /**一角硬币**/
- DIME(10),
- /**两角五分**/
- QUARTER(25),
- /**一块美金**/
- DOLLAR(100),
- /**药膏2元**/
- TOOTHPASTE(200),
- /**炸薯条75美分**/
- CHIPS(75),
- /**苏打水1元**/
- SODA(100),//
- /**肥皂5毛**/
- SOAP(50),
- ABORT_TRANSACTION{
- public int amount(){
- throw new RuntimeException("退出时不能获取余额!");
- }
- },
- STOP{
- public int amount(){
- throw new RuntimeException("关机时不能获取余额!");
- }
- };
- //金额
- int value;
- Input(int value){this.value = value;}
- Input(){}
- //返回该操作项的金额
- int amount(){return value;}
- /**
- * @return 随机获取的操作
- */
- public static Input randomSelection(){
- return values()[new Random(System.nanoTime()).nextInt(values().length)];
- }
- }
package enums;
import java.util.Random;
/**
* @描述 售货机可以接收的钞票金额和所有商品的价格
* @创建时间 2012-5-27
* @另请参照
*/
public enum Input {
/**五分硬币**/
NICKEL(5),
/**一角硬币**/
DIME(10),
/**两角五分**/
QUARTER(25),
/**一块美金**/
DOLLAR(100),
/**药膏2元**/
TOOTHPASTE(200),
/**炸薯条75美分**/
CHIPS(75),
/**苏打水1元**/
SODA(100),//
/**肥皂5毛**/
SOAP(50),
ABORT_TRANSACTION{
public int amount(){
throw new RuntimeException("退出时不能获取余额!");
}
},
STOP{
public int amount(){
throw new RuntimeException("关机时不能获取余额!");
}
};
//金额
int value;
Input(int value){this.value = value;}
Input(){}
//返回该操作项的金额
int amount(){return value;}
/**
* @return 随机获取的操作
*/
public static Input randomSelection(){
return values()[new Random(System.nanoTime()).nextInt(values().length)];
}
}
- package enums;
- import static enums.Input.*;
- import java.util.EnumMap;
- /**
- * 对自动售货机的状态分类
- */
- public enum Category {
- /**放入钞票**/
- MONEY(NICKEL,DIME,QUARTER,DOLLAR),
- /**选择商品**/
- ITEM_SELECTION(TOOTHPASTE,CHIPS,SODA,SOAP),
- /**退出**/
- QUIT_TRANSACTION(ABORT_TRANSACTION),
- /**关机**/
- SHUT_DOWN(STOP);
- private Input[] values;
- Category(Input... types){values = types;}
- public static EnumMap<Input, Category> categories = new EnumMap<Input, Category>(Input.class);
- public Input[] getValues(){
- return values;
- }
- //初始化自动售货机状态集合
- static {
- for (Category c : Category.class.getEnumConstants()) {
- for(Input input : c.values){
- categories.put(input, c);
- }
- }
- }
- /**返回该操作项所属状态**/
- public static Category categorize(Input input){
- return categories.get(input);
- }
- }
package enums;
import static enums.Input.*;
import java.util.EnumMap;
/**
* 对自动售货机的状态分类
*/
public enum Category {
/**放入钞票**/
MONEY(NICKEL,DIME,QUARTER,DOLLAR),
/**选择商品**/
ITEM_SELECTION(TOOTHPASTE,CHIPS,SODA,SOAP),
/**退出**/
QUIT_TRANSACTION(ABORT_TRANSACTION),
/**关机**/
SHUT_DOWN(STOP);
private Input[] values;
Category(Input... types){values = types;}
public static EnumMap<Input, Category> categories = new EnumMap<Input, Category>(Input.class);
public Input[] getValues(){
return values;
}
//初始化自动售货机状态集合
static {
for (Category c : Category.class.getEnumConstants()) {
for(Input input : c.values){
categories.put(input, c);
}
}
}
/**返回该操作项所属状态**/
public static Category categorize(Input input){
return categories.get(input);
}
}
- package enums;
- import static enums.Category.*;
- /**
- * 自动售货机
- */
- public class VendingMachine {
- //当前运行状态
- private static State state = State.RESTING;
- //当前余额
- private static int amount = 0;
- //当前选择商品
- private static Input selection = null;
- /**持续状态,不能做其他操作**/
- enum StateDuration{TRANSIENT}
- /**
- * 运行状态
- */
- enum State{
- /**初始界面**/
- RESTING{
- void next(Input input){
- switch (Category.categorize(input)) {
- case MONEY:
- amount += input.amount();
- System.out.println("放入金额:"+input.amount()+"美分");
- state = ADDING_MONEY;
- break;
- case SHUT_DOWN:
- state = TERMINAL;
- break;
- default:
- state = RESTING;
- break;
- }
- }
- },
- /**选择商品**/
- ADDING_MONEY{
- void next(Input input){
- switch (Category.categorize(input)) {
- case MONEY:
- amount += input.amount();
- System.out.println("再次放入金额:"+input.amount()+"美分,您的余额是:"+amount+"美分");
- break;
- case ITEM_SELECTION:
- selection = input;
- System.out.println("选择商品:"+input);
- if(amount < input.amount()){
- System.out.println("你的余额不够购买商品:"+input);
- state = ADDING_MONEY;
- }else state = DISPENSING;
- break;
- case QUIT_TRANSACTION:
- state = GIVING_CHANGE;
- break;
- case SHUT_DOWN:
- state = TERMINAL;
- break;
- default:
- state = ADDING_MONEY;
- break;
- }
- }
- },
- /**发出商品,交易成功**/
- DISPENSING(StateDuration.TRANSIENT){
- void next(){
- System.out.println("交易成功!请拿好您的商品:"+selection);
- //扣除购买商品的金额
- amount -= selection.amount();
- state = GIVING_CHANGE;
- }
- },
- /**找零**/
- GIVING_CHANGE(StateDuration.TRANSIENT){
- void next(){
- if(amount > 0){
- System.out.println("请拿好您的找零:"+amount+"美分");
- amount = 0;
- }
- state = TERMINAL;
- }
- },
- /**交易终止**/
- TERMINAL{
- void output(){
- System.out.println("交易结束");
- }
- };
- private boolean isTransient = false;
- /**当前是否是瞬时状态(即不可以做其他操作)**/
- public boolean isTransient(){return this.isTransient;}
- State(){}
- State(StateDuration stateDuration){this.isTransient = true;}
- //默认方法(在瞬时状态时做其他操作时被调用)
- void next(Input input){ System.out.println("该状态不能做其他操作!");}
- //默认方法(在非瞬时状态时不做操作时被调用)
- void next(){ System.out.println("请选择一个操作!");}
- //默认方法(查看余额)
- void output(){System.out.println("您的余额还剩:"+amount+"美分");}
- }
- //执行一个操作
- public static void run(Input gen){
- if(state!=State.TERMINAL){
- if(state.isTransient()){
- state.next();
- }else{
- state.next(gen);
- }
- }else{
- state.output();
- }
- }
- //测试
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- int i = 0;
- while(true){
- switch (state) {
- case RESTING:
- run(Enums.random(MONEY.getValues()));
- break;
- case ADDING_MONEY:
- //如果金额不足
- if(i > 0){
- run(Enums.random(MONEY.getValues()));
- i = 0;
- }else{
- run(Enums.random(ITEM_SELECTION.getValues()));
- i++;
- }
- break;
- case TERMINAL:
- run(Input.STOP);
- return;
- default:
- run(null);
- break;
- }
- }
- }
- }