状态机

本例使用状态机演示一个自动售货机的使用场景。

状态机接口: 

package statemachine;

/**
 * 状态机接口
 * 
 * @author guweiqiang
 * 2018年7月4日
 */
public interface State {
	
	/**
	 * 定义机器全部动作
	 */
	// 投入硬币
	void insertCoin();
	
	// 退回硬币
	void ejectCoin();
	
	// 转动摇柄
	void turnCrank();
	
	// 喷出糖果
	void dispense();
	
}

  

状态机类: 

package statemachine;

/**
 * 状态机类
 * 
 * @author guweiqiang
 * 2018年7月4日
 */
public class Machine {
	
	// 机器包含的所有状态
	private State nonCoinState; // 未投币状态
	private State hasCoinState; // 已投币状态
	private State soldState; // 正在出售状态
	private State soldOutState; // 已售光状态
	
	private State state; // 机器当前状态
	private int count; // 机器中当前的糖果数量
	
	/**
	 * 初始化状态机:引入所有的状态,并初始化糖果数量
	 * @param count
	 */
	public Machine(int count) {
		this.nonCoinState = new NonCoinState(this);
		this.hasCoinState = new HasCoinState(this);
		this.soldState = new SoldState(this);
		this.soldOutState = new SoldOutState(this);
		this.count = count;
		if(this.count>0) {
			this.state = nonCoinState;
		} else {
			this.state = soldOutState;
		}
	}
	
	// 投币
	public void insertCoin() {
		this.state.insertCoin();
	}
	
	// 退回硬币
	public void ejectCoin() {
		this.state.ejectCoin();
	}
	
	// 转动摇柄
	public void turnCrank() {
		this.state.turnCrank();
		this.state.dispense();
	}
	
	// 喷出糖果的内部处理
	public void releaseBall() {
		System.out.println("喷出了1个糖果。");
		if(this.count>0) {
			this.count--;
		}
	}

	// 各个状态的get方法
	public State getNonCoinState() {
		return nonCoinState;
	}

	public State getHasCoinState() {
		return hasCoinState;
	}

	public State getSoldState() {
		return soldState;
	}

	public State getSoldOutState() {
		return soldOutState;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public int getCount() {
		return count;
	}

}

 未投币状态类: 

package statemachine;

/**
 * 未投币状态类
 * 
 * @author guweiqiang
 * 2018年7月4日
 */
public class NonCoinState implements State {
	
	private Machine machine;
	
	public NonCoinState(Machine machine) {
		this.machine = machine;
	}

	// 投币
	public void insertCoin() {
		System.out.println("已投入硬币!");
		machine.setState(machine.getHasCoinState());
	}

	// 退回硬币
	public void ejectCoin() {
		System.out.println("没有可退回的硬币!");
	}

	// 转动摇柄
	public void turnCrank() {
		System.out.println("请先投币,再转动摇柄!");
	}

	// 喷出糖果
	public void dispense() {
		System.out.println("尚未投币!");
	}

}

 已投币状态类: 

package statemachine;

/**
 * 已投币状态类
 * 
 * @author guweiqiang
 * 2018年7月4日
 */
public class HasCoinState implements State {

	private Machine machine;

	public HasCoinState(Machine machine) {
		this.machine = machine;
	}
	
	// 投币
	public void insertCoin() {
		System.out.println("请不要重复投币!");
	}

	// 退回硬币
	public void ejectCoin() {
		System.out.println("已退回硬币!");
		machine.setState(machine.getNonCoinState()); // 重新设置为未投币状态
	}

	// 转动摇柄
	public void turnCrank() {
		System.out.println("转动了摇柄");
		machine.setState(machine.getSoldState()); // 设置机器状态为正在出售
	}

	// 喷出糖果
	public void dispense() {
		System.out.println("请转动摇柄!");
	}

}

 正在出售状态类: 

package statemachine;

/**
 * 正在出售状态类
 * 
 * @author guweiqiang
 * 2018年7月4日
 */
public class SoldState implements State {
	
	private Machine machine;

	public SoldState(Machine machine) {
		this.machine = machine;
	}
	
	// 投币
	public void insertCoin() {
		System.out.println("请等待,正在出货!");
	}

	// 退回硬币
	public void ejectCoin() {
		System.out.println("正在出货,无法退回硬币!");
	}

	// 转动摇柄
	public void turnCrank() {
		System.out.println("请不要重复转动摇柄!");
	}

	// 喷出糖果
	public void dispense() {
		// 喷出糖果
		machine.releaseBall();
		if(machine.getCount()>0) { // 还有糖果,可以继续出售
			machine.setState(machine.getNonCoinState());
		} else { // 已售光
			machine.setState(machine.getSoldOutState());
		}
	}

}

 已售光状态类: 

package statemachine;

/**
 * 已售光状态类
 * 
 * @author guweiqiang
 * 2018年7月4日
 */
public class SoldOutState implements State {

	private Machine machine;

	public SoldOutState(Machine machine) {
		this.machine = machine;
	}
	
	// 投币
	public void insertCoin() {
		System.out.println("糖果已售光,请不要投币!");
	}

	// 退回硬币
	public void ejectCoin() {
		System.out.println("没有可退回的硬币!");
	}

	// 转动摇柄
	public void turnCrank() {
		System.out.println("糖果已售光,请不要转动摇柄!");
		machine.setState(machine.getNonCoinState());
	}

	// 喷出糖果
	public void dispense() {
		System.out.println("糖果已售光!");
	}

}

  

测试类:

package statemachine;

/**
 * 测试类
 * 
 * @author guweiqiang
 * 2018年7月4日
 */
public class StateMachineTest {

	public static void main(String[] args) {
		Machine machine = new Machine(10);
		for (int i=0; i<12; i++) {
			System.out.println(i+": 当前糖果数量:" + machine.getCount());
			if(i==5) {
				machine.insertCoin();
				machine.ejectCoin();
				continue;
			}
			machine.insertCoin();
			machine.turnCrank();
		}

	}

}

 测试结果:

0: 当前糖果数量:10
已投入硬币!
转动了摇柄
喷出了1个糖果。
1: 当前糖果数量:9
已投入硬币!
转动了摇柄
喷出了1个糖果。
2: 当前糖果数量:8
已投入硬币!
转动了摇柄
喷出了1个糖果。
3: 当前糖果数量:7
已投入硬币!
转动了摇柄
喷出了1个糖果。
4: 当前糖果数量:6
已投入硬币!
转动了摇柄
喷出了1个糖果。
5: 当前糖果数量:5
已投入硬币!
已退回硬币!
6: 当前糖果数量:5
已投入硬币!
转动了摇柄
喷出了1个糖果。
7: 当前糖果数量:4
已投入硬币!
转动了摇柄
喷出了1个糖果。
8: 当前糖果数量:3
已投入硬币!
转动了摇柄
喷出了1个糖果。
9: 当前糖果数量:2
已投入硬币!
转动了摇柄
喷出了1个糖果。
10: 当前糖果数量:1
已投入硬币!
转动了摇柄
喷出了1个糖果。
11: 当前糖果数量:0
糖果已售光,请不要投币!
糖果已售光,请不要转动摇柄!
尚未投币!

相关推荐