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

过去的笔记链接
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状态。即下图:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Head First设计模式》是一本设计模式学习的畅销书籍。这本书的作者以幽默风格和易于理解的语言,引导读者深入了解面向对象设计的基础知识和常见设计模式的应用。 《Head First设计模式》首先介绍了面向对象设计原则,如开闭原则、依赖倒置原则和单一职责原则等。它强调了设计模式的重要性,这些模式是在常见的软件开发场景中提供解决方案的经验总结。 接着,书中详细介绍了23个经典的设计模式,分为创建型模式、结构型模式和行为型模式三个大类。每个模式都通过生动的例子和图表进行解释,使读者能够更好地理解其应用场景和使用方法。同时,还提供了一些实际案例,帮助读者将学到的知识应用到实际项目中。 《Head First设计模式》以问题驱动的方式进行讲解,通过解决具体的问题来引导读者理解模式的思想和用法。这种方式使得学习变得更加有趣和互动,读者可以通过参与问题的解决过程来更好地理解模式的实际应用。 总的来说,这本书是一本通俗易懂的设计模式入门教材。它以轻松幽默的方式向读者介绍了设计模式的基本概念和常见应用。读者通过阅读这本书,能够对设计模式有一个清晰的理解,并能够在实际项目中灵活运用。无论是初学者还是有一定经验的开发者,都能从中收获实用的知识和提升自己的设计能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值