版权声明:本文为博主原创文章,转载请注明出处 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状态。即下图: