自动售饮料机
状态:售空、有钱、没钱、出售中。
通过创建一个实例变量来持有状态值,并在方法内书写条件代码来处理不同状态。
我们需要处理所有发生的动作(状态的转换),动作包括:投钱、退钱、按出货按钮、出货。
package com.ez.other;
/**
* 通过一个实例变量来持有状态值,在方法内书写条件代码来处理不同状态。
* @author 窗外赏雪(EZ编程网)
*/
public class DrinkMachine {
// 售空
final static int SOLD_OUT = 0;
// 没钱
final static int NO_MONEY = 1;
// 有钱
final static int HAS_MONEY = 2;
// 出售中
final static int SELLING = 3;
int state = SOLD_OUT;
int count = 0;
public DrinkMachine(int count) {
// 初始化饮料瓶数
this.count = count;
// 如果瓶数>0,那么饮料机就处于无钱状态。
if (count > 0) {
state = NO_MONEY;
}
}
/**
* 投钱
*/
public void putMoney() {
if (state == HAS_MONEY) {
System.out.println("已经投钱,不需要再投了。");
} else if (state == NO_MONEY) {
state = HAS_MONEY;
System.out.println("投钱成功,欢迎选购。");
} else if (state == SOLD_OUT) {
System.out.println("饮料已经卖完了,不能投钱。");
} else if (state == SELLING) {
System.out.println("饮料出售中,请等待。");
}
}
/**
* 退款
*/
public void drawBack() {
if (state == HAS_MONEY) {
state = NO_MONEY;
System.out.println("退钱成功。");
} else if (state == NO_MONEY) {
System.out.println("没钱可以退。");
} else if (state == SOLD_OUT) {
System.out.println("没钱可以退。");
} else if (state == SELLING) {
System.out.println("饮料出售中,请等待。");
}
}
/**
* 按下出货按钮
*/
public void pressShipmentButton() {
if (state == HAS_MONEY) {
state = SELLING;//防止多次出货
System.out.println("出货中...");
drinkOut();
} else if (state == NO_MONEY) {
System.out.println("没钱不能出货。");
} else if (state == SOLD_OUT) {
System.out.println("已售空。");
} else if (state == SELLING) {
System.out.println("饮料出售中,请等待。");
}
}
/**
* 出货
*/
public void drinkOut() {
if (state == SELLING) {
System.out.println("出货成功,请在出货口取饮料");
count--;
if (count == 0) {
System.out.println("所有饮料都已售空");
state = SOLD_OUT;
} else {
state = NO_MONEY;
}
} else if (state == NO_MONEY) {
System.out.println("请投钱。");
} else if (state == HAS_MONEY) {
System.out.println("已出货。");
} else if (state == SOLD_OUT) {
System.out.println("已售空。");
}
}
public static void main(String[] args) {
// 初始化饮料机
DrinkMachine dm = new DrinkMachine(10);
dm.putMoney();
dm.pressShipmentButton();
dm.pressShipmentButton();
dm.drawBack();
dm.putMoney();
dm.drawBack();
dm.pressShipmentButton();
}
}
当需求发生变化,如饮料机多了一种状态,周四购买,买一送一。
之前使用一种考虑周详的方法实现饮料售卖机,但这并不意味着这份代码就容易扩展。
混乱的状态,必须在每个方法中判断新的状态来处理星期四的状态。
如果将每个状态的行为都放在各自的类中,那么每个状态只要实现它自己的动作就可以了。
我们定义一个State接口。在这个接口内,饮料售卖机的每个动作都有一个对应的方法。
为每个状态实现状态类。
状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
这个模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象,行为会随着内部状态的改变而改变。
实际上,我们是在使用组合通过简单引用不同的状态对象来造成类改变的假象。
package com.ez.biz;
/**
* 星期四状态,因为库存只有一件,所以买完就不送了。
* @author 窗外赏雪(EZ编程网)
*/
public class Test {
public static void main(String[] args) {
DrinkMachine dm=new DrinkMachine(1,4);
dm.putMoney();
dm.pressShipmentButton();
dm=new DrinkMachine(1,3);
dm.putMoney();
dm.pressShipmentButton();
}
}
package com.ez.biz;
import com.ez.State;
import com.ez.impl.HasMoneyState;
import com.ez.impl.IsThursdayState;
import com.ez.impl.NoMoneyState;
import com.ez.impl.SellingState;
import com.ez.impl.SoldOutState;
/**
* 使用组合,通过简单引用不同的状态对象,来产生不同的行为。
* @author 窗外赏雪(EZ编程网)
*/
public class DrinkMachine {
private State hasMoneyState;
private State isThursdayState;
private State noMoneyState;
private State sellingState;
private State soldOutState;
private State state = soldOutState;
private int count = 0;
private int dayIndex=0;
/**
* @param count 饮料库存
* @param dayIndex 星期几
*/
public DrinkMachine(int count,int dayIndex) {
hasMoneyState = new HasMoneyState(this);
isThursdayState = new IsThursdayState(this);
noMoneyState = new NoMoneyState(this);
sellingState = new SellingState(this);
soldOutState = new SoldOutState(this);
this.count=count;
if(this.count>0){
state=noMoneyState;
}
this.setDayIndex(dayIndex);
}
public void putMoney() {
state.putMoney();
}
public void drawBack() {
state.drawBack();
}
public void pressShipmentButton() {
state.pressShipmentButton();
state.drinkOut();
}
public void drinkOut(){
System.out.println("出货成功,请在出货口取饮料");
if(count>0){
count--;
}
}
public State getHasMoneyState() {
return hasMoneyState;
}
public void setState(State state) {
this.state = state;
}
public void setCount(int count) {
this.count = count;
}
public State getIsThursdayState() {
return isThursdayState;
}
public State getNoMoneyState() {
return noMoneyState;
}
public State getSellingState() {
return sellingState;
}
public State getSoldOutState() {
return soldOutState;
}
public State getState() {
return state;
}
public int getCount() {
return count;
}
public int getDayIndex() {
return dayIndex;
}
public void setDayIndex(int dayIndex) {
this.dayIndex = dayIndex;
}
}
package com.ez;
/**
* State接口定义了一个所有具体状态的共同接口
* 任何状态都实现这个接口,这样,状态之间可以互相替换。
* @author 窗外赏雪(EZ编程网)
*/
public interface State {
/**
* 投钱
*/
void putMoney();
/**
* 退款
*/
void drawBack();
/**
* 按下出货按钮
*/
void pressShipmentButton();
/**
* 出货
*/
void drinkOut();
}
package com.ez.impl;
import com.ez.State;
import com.ez.biz.DrinkMachine;
/**
* 有钱状态,按动按钮时,如果是星期四,就切换到星期四状态,使用星期四的活动。
* @author 窗外赏雪(EZ编程网)
*/
public class HasMoneyState implements State {
private DrinkMachine drinkMachine;
public HasMoneyState(DrinkMachine drinkMachine) {
this.drinkMachine=drinkMachine;
}
@Override
public void putMoney() {
System.out.println("已经投钱,不需要再投了。");
}
@Override
public void drawBack() {
System.out.println("退钱成功。");
drinkMachine.setState(drinkMachine.getNoMoneyState());
}
@Override
public void pressShipmentButton() {
System.out.println("出货中...");
if(drinkMachine.getDayIndex()==4){
drinkMachine.setState(drinkMachine.getIsThursdayState());
}else{
drinkMachine.setState(drinkMachine.getSellingState());
}
}
@Override
public void drinkOut() {
}
}
package com.ez.impl;
import com.ez.State;
import com.ez.biz.DrinkMachine;
/**
* 周四状态,可以出货,买一送一。其他行为都没用到
* @author 窗外赏雪(EZ编程网)
*/
public class IsThursdayState implements State {
private DrinkMachine drinkMachine;
public IsThursdayState(DrinkMachine drinkMachine) {
this.drinkMachine=drinkMachine;
}
@Override
public void putMoney() {
}
@Override
public void drawBack() {
}
@Override
public void pressShipmentButton() {
}
@Override
public void drinkOut() {
System.out.println("嗨,今天是星期四,所有饮料买一送一,售完为止。");
drinkMachine.drinkOut();
if(drinkMachine.getCount()==0){
System.out.println("售空就不送了");
drinkMachine.setState(drinkMachine.getSoldOutState());
}else{
drinkMachine.drinkOut();
if(drinkMachine.getCount()>0){
drinkMachine.setState(drinkMachine.getNoMoneyState());
}else{
System.out.println("售空了");
drinkMachine.setState(drinkMachine.getSoldOutState());
}
}
}
}
package com.ez.impl;
import com.ez.State;
import com.ez.biz.DrinkMachine;
/**
* 没钱状态,可以投钱,变成有钱状态。
* @author 窗外赏雪(EZ编程网)
*/
public class NoMoneyState implements State {
private DrinkMachine drinkMachine;
public NoMoneyState(DrinkMachine drinkMachine) {
this.drinkMachine=drinkMachine;
}
@Override
public void putMoney() {
System.out.println("投钱成功,欢迎选购。");
drinkMachine.setState(drinkMachine.getHasMoneyState());
}
@Override
public void drawBack() {
System.out.println("没钱可以退。");
}
@Override
public void pressShipmentButton() {
System.out.println("没钱不能出货。");
}
@Override
public void drinkOut() {
}
}
package com.ez.impl;
import com.ez.State;
import com.ez.biz.DrinkMachine;
/**
* 出售中状态,出售中状态可以出货
* @author 窗外赏雪(EZ编程网)
*/
public class SellingState implements State{
private DrinkMachine drinkMachine;
public SellingState(DrinkMachine drinkMachine) {
this.drinkMachine=drinkMachine;
}
@Override
public void putMoney() {
System.out.println("饮料出售中,请等待。");
}
@Override
public void drawBack() {
System.out.println("饮料出售中,请等待。");
}
//防止出多瓶饮料
@Override
public void pressShipmentButton() {
System.out.println("饮料出售中,请等待。");
}
@Override
public void drinkOut() {
drinkMachine.drinkOut();
if(drinkMachine.getCount()>0){
drinkMachine.setState(drinkMachine.getNoMoneyState());
}else{
System.out.println("所有饮料都已售空");
drinkMachine.setState(drinkMachine.getSoldOutState());
}
}
}
package com.ez.impl;
import com.ez.State;
import com.ez.biz.DrinkMachine;
public class SoldOutState implements State {
private DrinkMachine drinkMachine;
public SoldOutState(DrinkMachine drinkMachine) {
this.drinkMachine=drinkMachine;
}
@Override
public void putMoney() {
System.out.println("饮料已经卖完了,不能投钱。");
}
@Override
public void drawBack() {
System.out.println("没钱可以退。");
}
@Override
public void pressShipmentButton() {
System.out.println("已售空。");
}
@Override
public void drinkOut() {
}
}