Head First设计模式读书笔记九 第十章 状态模式

版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/u011109881/article/details/82828163

过去的笔记链接
https://blog.csdn.net/u011109881/article/details/60158137

状态模式实例

用Java设计糖果机吧
大致流程:
在这里插入图片描述
上图中,有四种状态:没有硬币,有硬币,准备售出状态以及糖果售罄状态。而控制糖果机状态转换的则是各种动作(Action),这些动作分别是投入硬币,超时判断,转动曲柄,判断糖果决定是否售出。
GumballMachine类

public class GumballMachine {
	//define 4 states
	private final int  SOLD_OUT=0;
	private final int  NO_COIN=1;
	private final int  HAS_COIN=2;
	private final int  START_TO_SOLD=3;
	
	int stateNow = SOLD_OUT;
	int count = 0;
	public GumballMachine(int count) {
		if (count > 0){
			stateNow = NO_COIN;
		}
		this.count = count;
	}
	
	//define 4 actions
	public void insertCoin(){
		switch (stateNow) {
		case SOLD_OUT:
			System.out.println("机器售罄,请勿投币"+getState());
			break;
		case NO_COIN:
			//正常case
			stateNow = HAS_COIN;
			System.out.println("你投入了硬币"+getState());
			break;
		case HAS_COIN:
			System.out.println("你已经投过币了,无法投币"+getState());
			break;
		case START_TO_SOLD:
			System.out.println("请稍后投币,机器处理中"+getState());
			break;
		default:
			System.out.println("unknown state");
			break;
		}
	}
	
	public void ejectCoin(){
		switch (stateNow) {
		case SOLD_OUT:
			System.out.println("你没有投币"+getState());
			break;
		case NO_COIN:
			System.out.println("你没有投币"+getState());
			break;
		case HAS_COIN:
			//正常case
			stateNow = NO_COIN;
			System.out.println("等待超时,退币。或者你按下了退币健"+getState());
			break;
		case START_TO_SOLD:
			System.out.println("你已经旋转曲柄,机器已经准备售出,无法退币"+getState());
			break;
		default:
			System.out.println("unknown state");
			break;
		}
	}
	
	public void turnCrank(){
		switch (stateNow) {
		case SOLD_OUT:
			System.out.println("糖果售罄,请勿操作");
			break;
		case NO_COIN:
			System.out.println("请先投币");
			break;
		case HAS_COIN:
			//正常case
			stateNow = START_TO_SOLD;
			System.out.println("你转动了曲柄"+getState());
			break;
		case START_TO_SOLD:
			System.out.println("机器处理中,请勿操作");
			break;
		default:
			System.out.println("unknown state");
			break;
		}
	}
	
	//发放糖果
	public void dispense(){
		switch (stateNow) {
		case SOLD_OUT:
			System.out.println("请正确操作本机");
			break;
		case NO_COIN:
			System.out.println("请先投币");
			break;
		case HAS_COIN:
			System.out.println("先转动曲柄");
			break;
		case START_TO_SOLD:
			//正常case
			count --;
			if(count > 0){
				stateNow = NO_COIN;
				System.out.println("售出糖果"+getState());
			}else{
				stateNow = SOLD_OUT;
				System.out.println("售出糖果"+getState());
			}
			
			break;
		default:
			System.out.println("unknown state");
			break;
		}
	}
	
	public String getState(){
		switch (stateNow) {
		case SOLD_OUT:
			return (" 目前状态:糖果售罄状态");
		case NO_COIN:
			return  (" 目前状态:没有硬币状态");
		case HAS_COIN:
			return (" 目前状态:有硬币状态");
		case START_TO_SOLD:
			return (" 目前状态:准备售出状态");

		default:
			return " 目前状态:未知状态";
		}
	}
}

测试类

public class Test {

	public static void main(String[] args) {
		GumballMachine gumballMachine = new GumballMachine(3);
		gumballMachine.insertCoin();
		gumballMachine.turnCrank();
		gumballMachine.dispense();
		System.out.println("================");
		gumballMachine.dispense();
		gumballMachine.turnCrank();
		gumballMachine.insertCoin();
		System.out.println("================");

		gumballMachine.insertCoin();
		gumballMachine.turnCrank();
		gumballMachine.dispense();
		System.out.println("================");
		gumballMachine.insertCoin();
		gumballMachine.turnCrank();
		gumballMachine.dispense();
		System.out.println("================");
		gumballMachine.insertCoin();
		gumballMachine.turnCrank();
		gumballMachine.dispense();
	}
}

测试结果

你投入了硬币 目前状态:有硬币状态
你转动了曲柄 目前状态:准备售出状态
售出糖果 目前状态:没有硬币状态
================
请先投币
请先投币
你投入了硬币 目前状态:有硬币状态
================
你已经投过币了,无法投币 目前状态:有硬币状态
你转动了曲柄 目前状态:准备售出状态
售出糖果 目前状态:没有硬币状态
================
你投入了硬币 目前状态:有硬币状态
你转动了曲柄 目前状态:准备售出状态
售出糖果 目前状态:糖果售罄状态
================
机器售罄,请勿投币 目前状态:糖果售罄状态
糖果售罄,请勿操作
请正确操作本机

新加功能,中奖机制

客户希望给机器添加中奖机制,即用户每次买糖果,有10%的几率获得2个糖果.
我们可以看到GumballMachine这个类太过复杂,状态转换全都包含其中,因此我们需要做一些改变了。
1.定义状态接口

public interface State {
	//define 4 actions
	public void insertCoin();
	
	public void ejectCoin();
	
	public void turnCrank();
	
	public void dispense();
	
	public String getState();
}

2.重新实现GumballMachine类

public class GumballMachine {
	// define 4 states
	State soldOutState;
	State hasCoinState;
	State noCoinState;
	State soldState;
	State winnerState;
	int count = 0;
	State stateNow = soldOutState;

	public GumballMachine(int count) {
		soldOutState = new SoldOutState(this);
		hasCoinState = new HasCoinState(this);
		noCoinState = new NoCoinState(this);
		soldState = new SoldState(this);
		winnerState = new WinnerState(this);
		if (count > 0) {
			stateNow = noCoinState;
		}
		this.count = count;
	}

	public void insertCoin() {
		stateNow.insertCoin();
	}

	public void ejectCoin() {
		stateNow.ejectCoin();
	}

	public void turnTrunk() {
		stateNow.turnCrank();
		stateNow.dispense();
	}

	void setState(State state) {
		stateNow = state;
	}

	void releaseBall() {
		if (count > 0) {
			count--;
			System.out.println("A gumball rolling out the slot...");
		} else {
			System.out.println("release ball failed");
		}
	}

	public State getSoldOutState() {
		return soldOutState;
	}

	public State getHasCoinState() {
		return hasCoinState;
	}

	public State getNoCoinState() {
		return noCoinState;
	}

	public State getSoldState() {
		return soldState;
	}

	public State getWinnerState() {
		return winnerState;
	}

	public int getCount() {
		return count;
	}

	public State getStateNow() {
		return stateNow;
	}
	
	
}

3.实现状态类:
将原先

	private final int  SOLD_OUT=0;
	private final int  NO_COIN=1;
	private final int  HAS_COIN=2;
	private final int  START_TO_SOLD=3;

的设计改到类中;这样,原先我们是操作时需要判断当前状态。而现在我们是状态被固定,需要看能进行哪些操作(状态控制动作)。而且,我们不需要主动控制状态,状态由代码自动控制。

public class HasCoinState implements State {
	Random randomWinner = new Random(System.currentTimeMillis());
	GumballMachine gumballMachine;
	public HasCoinState(GumballMachine gumballMachine) {
		this.gumballMachine = gumballMachine;
	}

	public void insertCoin() {
		System.out.println("你已经投过币了");
	}

	public void ejectCoin() {
		System.out.println("你请求了退币");
		gumballMachine.setState(gumballMachine.getNoCoinState());
	}

	public void turnCrank() {
		System.out.println("你转动了曲柄");
		int winner = randomWinner.nextInt(10);
		if(winner ==0 && gumballMachine.getCount()>1){
			gumballMachine.setState(gumballMachine.getWinnerState());
		}else{
			gumballMachine.setState(gumballMachine.getSoldState());
		}
	}

	public void dispense() {
		System.out.println("请先转动曲柄");
	}

	public String getState() {
		return this.getClass().getName();
	}

}
public class NoCoinState implements State {
	GumballMachine gumballMachine;
	public NoCoinState(GumballMachine gumballMachine) {
		this.gumballMachine = gumballMachine;
	}

	public void insertCoin() {
		System.out.println("你投币了");
		gumballMachine.setState(gumballMachine.getHasCoinState());
	}

	public void ejectCoin() {
		System.out.println("你还没有投币");
	}

	public void turnCrank() {
		System.out.println("你还没有投币,转杆无效");
	}

	public void dispense() {
		System.out.println("还没有投币,不能发放糖果");
	}

	public String getState() {
		return this.getClass().getName();
	}

}

public class SoldOutState implements State {
	GumballMachine gumballMachine;
	public SoldOutState(GumballMachine gumballMachine) {
		this.gumballMachine = gumballMachine;
	}
	public void insertCoin() {
		System.out.println("糖果售罄,请勿操作");
	}

	public void ejectCoin() {
		System.out.println("糖果售罄,请勿操作");
	}

	public void turnCrank() {
		System.out.println("糖果售罄,请勿操作");
	}

	public void dispense() {
		System.out.println("糖果售罄,请勿操作");
	}

	public String getState() {
		return this.getClass().getName();
	}

}

public class SoldState implements State {
	GumballMachine gumballMachine;
	public SoldState(GumballMachine gumballMachine) {
		this.gumballMachine = gumballMachine;
	}

	public void insertCoin() {
		System.out.println("机器处理中,请稍后");
	}

	public void ejectCoin() {
		System.out.println("机器已经处理,无法操作");
	}

	public void turnCrank() {
		System.out.println("你已经转动过曲柄了");
	}

	public void dispense() {
		gumballMachine.releaseBall();
		if(gumballMachine.count>0){
			gumballMachine.setState(gumballMachine.getNoCoinState());
			System.out.println("发放糖果");
		}else{
			System.out.println("发放糖果完毕,糖果售罄");
			gumballMachine.setState(gumballMachine.getSoldOutState());
		}
	}

	public String getState() {
		return this.getClass().getName();
	}

}

public class WinnerState implements State {
	GumballMachine gumballMachine;
	public WinnerState(GumballMachine gumballMachine) {
		this.gumballMachine = gumballMachine;
	}

	public void insertCoin() {
		System.out.println("机器正在处理,请稍后投币");
	}

	public void ejectCoin() {
		System.out.println("机器正在处理,无法退币");
	}

	public void turnCrank() {
		System.out.println("机器正在处理,无法操作");
	}

	public void dispense() {
		gumballMachine.releaseBall();
		if(gumballMachine.getCount() == 0){
			gumballMachine.setState(gumballMachine.getSoldOutState());
		}else{
			System.out.println("你获得了奖励");
			gumballMachine.releaseBall();
			if(gumballMachine.getCount() == 0){
				gumballMachine.setState(gumballMachine.getSoldOutState());
			}else{
				gumballMachine.setState(gumballMachine.getNoCoinState());
			}
		}
	}

	public String getState() {
		return null;
	}

}

4.修改测试类

public class Test {

	public static void main(String[] args) {
		GumballMachine gumballMachine = new GumballMachine(5);
		for(int i =0;i<5; i++){
			gumballMachine.insertCoin();
			gumballMachine.turnTrunk();
			System.out.println(gumballMachine.getStateNow().getState()+"---------------");
		}
	}
}

5.测试结果:

你投币了
你转动了曲柄
A gumball rolling out the slot...
发放糖果
bean.NoCoinState---------------
你投币了
你转动了曲柄
A gumball rolling out the slot...
发放糖果
bean.NoCoinState---------------
你投币了
你转动了曲柄
A gumball rolling out the slot...
发放糖果
bean.NoCoinState---------------
你投币了
你转动了曲柄
A gumball rolling out the slot...
你获得了奖励
A gumball rolling out the slot...
bean.SoldOutState---------------
糖果售罄,请勿操作
糖果售罄,请勿操作
糖果售罄,请勿操作
bean.SoldOutState---------------

状态模式的简单分析

状态模式存在几个简单部分:
context state
Context意为上下文,在这里即是GumballMachine,而state在这里就是各个state的实现类了。
可以看到GumballMachine中包含了各类状态的引用实例,而GumballMachine也存在自己当前状态的实例
GumballMachine类的操作看上去是交给了State实现类,但实际上,State中存在Context的引用,State实现类在操作时通过GumballMachine引用来控制GumballMachine状态。即下图:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u011109881/article/details/82828163