现在的位置: 首页 > 综合 > 正文

java 枚举高级应用之状态机

2013年05月19日 ⁄ 综合 ⁄ 共 5713字 ⁄ 字号 评论关闭

转载自: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

抱歉!评论已关闭.