`

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从哪里来?

相关推荐

    高阶Java-Java枚举类型 enum 应用详解

    在Java编程语言中,枚举(enum)是一种特殊的类,用于定义一组固定的常量。...枚举的这些特性使其在设计模式、数据模型、状态机等多种场景中都有广泛应用。理解并熟练运用Java枚举,能显著提高代码质量和可维护性。

    Java中的枚举类型Enum示例源代码

    枚举类型还可以用于实现策略模式、状态机等设计模式,提供了比常量类更安全、更灵活的解决方案。 总之,Java的枚举类型`Enum`不仅提供了对常量集的封装,还具备了类的所有功能,包括方法、构造函数和继承。它极大地...

    JAVA核心技术 卷1 高级特性

    枚举在设计模式、状态机等场景中非常有用。 注解(Annotation)是元数据的一种形式,它提供了向编译器或JVM传递信息的方式。Java提供了标准注解如`@Override`, `@Deprecated`, `@ SuppressWarnings`,同时允许...

    高级java工程师面试考纲,java高级工程师进阶知识地图

    ### 高级Java工程师面试考纲详解 #### Java基础 1. **Collection和Map** - **继承体系**:理解`Collection`接口与其子接口如`List`、`Set`的关系,以及`Map`接口的不同实现类之间的联系。 - **具体实现**:深入...

    第十四章枚举

    3. 状态机:枚举在状态机的设计中非常有用,每个枚举值代表一种状态。 4. 网络协议:在网络编程中,枚举常用于定义协议中的各种标志和状态。 通过学习枚举这一概念,开发者可以更好地组织代码,提高代码的可读性和...

    java飞机大战游戏

    开发者可以使用枚举类型(enum)来表示不同的游戏状态,并通过状态机模式来管理这些状态。 8. **资源管理**:游戏中的图片、音频等资源需要被正确加载和释放,避免内存泄漏。Java提供了多种I/O流类来读取文件,同时...

    单机连连看 java源代码

    开发者需要设计一种机制来跟踪和管理这些状态,可能使用枚举类型或布尔变量来表示。 6. **编译与构建过程**:`.classpath`和`.project`文件是Eclipse IDE的项目配置文件,它们定义了项目的依赖和构建路径。`....

    XX.rar_java飞机大战

    这些状态可以通过枚举类型或状态机模式来管理。 9. **对象池设计**:为了提高性能,开发者可能采用了对象池设计模式,预先创建一部分对象并复用,而不是频繁地创建和销毁,如子弹和敌机的实例。 10. **游戏保存和...

    贪食蛇源代码(java实现)及java文件

    6. **状态机**:游戏的状态管理通常用到状态机的概念,蛇的不同状态(如移动、吃食物、死亡)可以通过状态机进行逻辑切换。 7. **集合与数据结构**:蛇的身体可能用链表或数组列表来存储,每次移动时更新这些数据...

    基于Java的记忆游戏

    开发者可能使用条件语句(if-else)、switch语句或枚举类型来实现状态机,确保游戏流程的正确执行。 **5. 存储与持久化** 为了保存玩家的成绩,游戏可能采用了文件存储或数据库技术。Java提供了多种文件I/O流API,...

    java2D忍者游戏demo源码_java_游戏_

    6. **游戏状态管理**:游戏可能包含多个状态(如开始、游戏进行、暂停、结束),开发者可能使用枚举或状态机来管理这些状态的切换。 7. **对象结构**:游戏中的各种元素(如角色、敌人、道具)可能被设计为面向对象...

    基于Java的源码-电梯模拟程序 v2.0.zip

    总之,这个基于Java的电梯模拟程序v2.0不仅能够帮助我们掌握Java编程基础,还能深入理解多线程、并发控制、状态机设计等高级概念,对于提升编程技能和解决问题的能力具有极大的实践价值。通过分析和学习这个项目的...

    OCP java SE7 Programmer II Certification Guide

    - **枚举类型的高级应用**:介绍枚举类型在实际编程中的灵活运用,比如利用枚举类型简化状态机的设计。 #### 高级类设计技术要点 - **泛型的高级话题**:深入探讨泛型通配符、类型边界等高级特性,以及它们在实际...

    贪吃蛇java swing

    这些状态可以通过使用枚举类型或者状态机来管理,确保游戏逻辑的正确执行。 7. **数据结构与算法**: 蛇的身体由一系列坐标点组成,可以使用数组、链表或其他数据结构来表示。移动和碰撞检测涉及到对这些数据结构的...

    Java工作实用篇.pdf

    - 用于定义状态机的状态。 - 作为配置项的枚举列表。 #### 8. 常用前端框架简介 - **框架概览**: 包括React、Vue、Angular等主流前端框架的介绍及其核心特点。 - **适用场景**: - 快速搭建Web应用程序界面。 - ...

    贪吃蛇游戏java版源码

    Swing是建立在AWT之上的更高级的库,提供了更多的组件和功能。在这个项目中,你会看到如何使用JFrame、JPanel、JButton等Swing组件来构建游戏界面。 3. **事件处理**:游戏的交互性主要通过事件监听器实现,例如...

    这是一个基于java的飞机大战类小游戏.zip

    开发者通常会使用枚举类型(enum)来定义游戏状态,并用状态机模型来管理这些状态之间的切换。 综上所述,这个基于Java的飞机大战小游戏不仅展示了Java语言的基础特性,还涵盖了面向对象设计、多线程编程、GUI开发...

    java写的飞机大战小游戏.zip

    Java中的枚举类型可以用来表示这些状态,并通过条件判断进行状态切换。游戏状态管理确保了游戏逻辑的清晰性和可维护性。 3. **游戏对象**:飞机、子弹、敌人等都是游戏对象,它们有自己的属性(如位置、速度、生命...

    finite-state-machine:有限状态机引擎

    - **使用库**:Java社区中有许多专门用于实现有限状态机的库,如jFSM、Stateless等,它们提供了更高级的功能和抽象,可以简化开发过程。 在实际应用中,有限状态机可以帮助我们处理复杂的问题,例如网络协议解析中...

    基于Java Swing的一个飞机躲避子弹小游戏.zip

    6. **状态管理**:游戏可能有多种状态,如开始、暂停、游戏结束等,这些状态的管理可以通过枚举类型或者布尔变量来实现。 7. **资源管理**:游戏可能涉及到图片、音频等资源,Java提供`ImageIcon`类来加载和显示...

Global site tag (gtag.js) - Google Analytics