《HeadFirst设计模式》第十章-状态模式

本文介绍了如何使用状态模式重构糖果机软件系统以应对需求变更。最初的设计包含条件分支,导致代码不易扩展。通过定义状态接口和创建对应状态类,实现了行为的封装,使代码更易于维护。新设计中,糖果机的状态由State对象表示,行为委托给状态类,减少了if语句,提高了代码的可读性和可扩展性。
摘要由CSDN通过智能技术生成

1.声明

设计模式中的设计思想、图片和部分代码参考自《Head First设计模式》作者Eric Freeman & Elisabeth Freeman & Kathy Siezza & Bert Bates。

在这里我只是对这本书进行学习阅读,并向大家分享一些心得体会。

2.需求

有一家糖果机公司想让我们帮他们做一套软件系统供糖果机使用,并且他们想要达成如下效果。

这是一张状态图,每个圆圈表示糖果机的一种状态,每个箭头表示状态的转换过程。例如对于糖果机来说,我们投入25分钱,那么糖果机就由"没有25分钱" ——> "有25分钱"这个状态。

如何由状态图得到真正的代码

第一步:

列出糖果机所有可能的状态。经过分析,可以得到如下四种状态:

没有25分钱
有25分钱
糖果售空
售出糖果

第二步:

为每个状态都赋予一个常量值,并且再定义一个变量,表示当前所处的状态:

//售空
final static int SOLD_OUT = 0;
//无硬币
final static int NO_QUARTER = 1;
//有硬币
final static int HAS_QUARTER = 2;
//售出
final static int SOLD = 3;
 
//糖果机目前所处的状态,初始时默认为无糖果的状态
int state = SOLD_OUT;

第三步:

列出糖果所可能接收到一切动作(指令):

投入25分钱
退回25分钱
转动曲柄
发放糖果

第四步:

创建一个类,这个类的作用就像是一个状态机。对每一个动作( 投入25分钱 ),都需要创建一个对应的方法( insertQuarter() )。

但是糖果机的状态不同,即使接收到相同的动作,那么结果也是不同的。所以在每个方法中,都需要用if分支做判断,根据当前所处的状态,来判断接收到此指令后下个状态是什么。

//投入硬币
public void insertQuarter() {
	if (state == HAS_QUARTER) {
		System.out.println("You can't insert another quarter");
	} else if (state == NO_QUARTER) {
		state = HAS_QUARTER;
		System.out.println("You inserted a quarter");
	} else if (state == SOLD_OUT) {
		System.out.println("You can't insert a quarter, the machine is sold out");
	} else if (state == SOLD) {
        System.out.println("Please wait, we're already giving you a gumball");
	}
}

3.最初的代码设计

糖果机:

//糖果机
public class GumballMachine {
 
	//售空
	final static int SOLD_OUT = 0;
	//无硬币
	final static int NO_QUARTER = 1;
	//有硬币
	final static int HAS_QUARTER = 2;
	//售出
	final static int SOLD = 3;
 
	//糖果机目前所处的状态
	int state = SOLD_OUT;
	//记录糖果机中当前的糖果数量
	int count = 0;
  
	public GumballMachine(int count) {
		this.count = count;
		if (count > 0) {
			state = NO_QUARTER;
		}
	}
  
	//----------------------四种动作----------------------
	//投入硬币
	public void insertQuarter() {
		if (state == HAS_QUARTER) {
			System.out.println("You can't insert another quarter");
		} else if (state == NO_QUARTER) {
			state = HAS_QUARTER;
			System.out.println("You inserted a quarter");
		} else if (state == SOLD_OUT) {
			System.out.println("You can't insert a quarter, the machine is sold out");
		} else if (state == SOLD) {
        	System.out.println("Please wait, we're already giving you a gumball");
		}
	}

	//退回硬币
	public void ejectQuarter() {
		if (state == HAS_QUARTER) {
			System.out.println("Quarter returned");
			state = NO_QUARTER;
		} else if (state == NO_QUARTER) {
			System.out.println("You haven't inserted a quarter");
		} else if (state == SOLD) {
			System.out.println("Sorry, you already turned the crank");
		} else if (state == SOLD_OUT) {
        	System.out.println("You can't eject, you haven't inserted a quarter yet");
		}
	}
 
	//转动曲柄
	public void turnCrank() {
		if (state == SOLD) {
			System.out.println("Turning twice doesn't get you another gumball!");
		} else if (state == NO_QUARTER) {
			System.out.println("You turned but there's no quarter");
		} else if (state == SOLD_OUT) {
			System.out.println("You turned, but there are no gumballs");
		} else if (state == HAS_QUARTER) {
			System.out.println("You turned...");
			state = SOLD;
			dispense();
		}
	}
 
	//发放糖果
	private void dispense() {
		if (state == SOLD) {
			System.out.println("A gumball comes rolling out the slot");
			count = count - 1;
			if (count == 0) {
				System.out.println("Oops, out of gumballs!");
				state = SOLD_OUT;
			} else {
				state = NO_QUARTER;
			}
		} else if (state == NO_QUARTER) {
			System.out.println("You need to pay first");
		} else if (state == SOLD_OUT) {
			System.out.println("No gumball dispensed");
		} else if (state == HAS_QUARTER) {
			System.out.println("No gumball dispensed");
		}
	}
 
	//----------------------其他方法----------------------
	//充值
	public void refill(int numGumBalls) {
		this.count = numGumBalls;
		state = NO_QUARTER;
	}

	public String toString() {
		StringBuffer result = new StringBuffer();
		result.append("\nMighty Gumball, Inc.");
		result.append("\nJava-enabled Standing Gumball Model #2004\n");
		result.append("Inventory: " + count + " gumball");
		if (count != 1) {
			result.append("s");
		}
		result.append("\nMachine is ");
		if (state == SOLD_OUT) {
			result.append("sold out");
		} else if (state == NO_QUARTER) {
			result.append("waiting for quarter");
		} else if (state == HAS_QUARTER) {
			result.append("waiting for turn of crank");
		} else if (state == SOLD) {
			result.append("delivering a gumball");
		}
		result.append("\n");
		return result.toString();
	}
}

测试方法:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琴瘦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值