java 枚举高级应用之状态机

转载自:http://wangning1125.iteye.com/blog/1542249


枚举类型非常适合用来创建状态机,一个状态机通常可以拥有有限的几个状态,他通常根据输入,从一个状态进入到下一个状态。

下面是一个用枚举实现的自动售货机的例子,很简陋,但是表达清楚了意思就差不多了,也希望各位看官能指出不足之处。


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.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;
}
}
}
}

转载自:http://wangning1125.iteye.com/blog/1542249

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值