`

java 枚举高级应用之状态机

 
阅读更多

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

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

 

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

 

测试写的不怎么好。没那么多时间。

分享到:
评论
4 楼 Mr.San 2016-07-27  
binbinyouli 写道
run(Enums.random(MONEY.getValues())); 
Enums从哪里来?


class Enums
{
	private static java.util.Random rand = new java.util.Random();

	public static <T extends Enum<T>> T random(Class<T> ec) {
		System.out.print("随机抽取" + ec + "中的一个元素:");
		return random(ec.getEnumConstants());
	}

	public static <T> T random(T[] values){
		int index = rand.nextInt(values.length);
		System.out.println(".index: " + index);

		return values[index];
	}
}
3 楼 Mr.San 2016-07-27  
class Enums
{
	private static java.util.Random rand = new java.util.Random();

	public static <T extends Enum<T>> T random(Class<T> ec) {
		System.out.print("随机抽取" + ec + "中的一个元素:");
		return random(ec.getEnumConstants());
	}

	public static <T> T random(T[] values){
		int index = rand.nextInt(values.length);
		System.out.println(".index: " + index);

		return values[index];
	}
}
2 楼 nocb 2013-05-12  
对,Enums  没有
1 楼 binbinyouli 2013-03-25  
run(Enums.random(MONEY.getValues())); 
Enums从哪里来?

相关推荐

Global site tag (gtag.js) - Google Analytics