状态模式是在程序开发时,经常用到的模式。如果没有应用过,而实现业务功能。那你也一定是按照状态模式的路子走的,只不过你没有感觉到而已。它的实现,是要根据对象的内部状态变化,而自动执行相应的功能。
费话就不说了,请看一下源代码,这也是我研究设计模式时看到的一个例子,把其翻译成中文,使个位网友能够看懂些,由于水平有限,只能达到这样,还希望网友多指证,也算是抄来的哈哈,谢谢啊。
public class GumballMachine {
//这就是那4个状态,每个状态都用一个不同的整数代表,他们符合状态图
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; //这个变量用来追踪机器内的糖果数目
//构造器初始糖果库存量当做参数,如果库存不为0的话,机器就进入"没有钱"的状态,等着你向里投钱
public GumballMachine(int count) {
this.count = count;
if (count > 0) {
state = NO_QUARTER;
}
}
//当把钱投入进来,就会执行这里
public void insertQuarter() {
if (state == HAS_QUARTER) {
//如果此时的状态为有钱状态,则通知顾客
System.out.println("你不能再向糖果机里投钱了");
} else if (state == NO_QUARTER) {
//如果是在"没有25分钱"的状态下,我们就接受25分钱,并将状态转换到"有25分钱"
state = HAS_QUARTER;
System.out.println("你可以向糖果机里投钱");
} else if (state == SOLD_OUT) {
//如果糖果售完,就拒绝收钱
System.out.println("糖果已经卖完,不能再向里投钱了");
} else if (state == SOLD) {
//如果顾客买到糖果,就需要稍等下,好让状态转换完毕,恢复到"没有25分钱"的状态
System.out.println("已向你卖出一个糖果,请稍等,再向里投钱。");
}
}
//现在,如果顾客试着退回25分钱...
public void ejectQuarter() {
if (state == HAS_QUARTER) {
//如果有25分钱,就退钱,回到"没有25分钱"的状态
System.out.println("退钱成功");
state = NO_QUARTER;
} else if (state == NO_QUARTER) {
//如果没有25分钱,当然不能退回
System.out.println("没有钱,你不能退钱");
} else if (state == SOLD) {
//如果顾客已经转动手柄,就不能退钱了,他已经拿到糖果了
state = NO_QUARTER;
System.out.println("对不起,糖果已经卖出不能退钱。");
} else if (state == SOLD_OUT) {
//如果糖果售完,就不可能接受25分钱,当然也不可能退钱
System.out.println("对不起,糖果已经卖完不能退钱");
}
}
//顾客试着转动手柄...
public void turnCrank() {
if (state == SOLD) {
//别想骗过机器拿2次糖果
System.out.println("不能再给你了");
} else if (state == NO_QUARTER) {
//我们需要先投入25分钱
System.out.println("你没有投钱糖果不能卖给你");
} else if (state == SOLD_OUT) {
//没有糖果了
System.out.println("糖果机中没有糖果了,你不能进行交易。");
} else if (state == HAS_QUARTER) {
//成功!他拿到糖果了.改变状态到"售出糖果",然后调用机器的dispense()方法
System.out.println("请稍等,一会糖果你就可以拿到了...");
state = SOLD;
dispense();
}
}
//发放糖果
public void dispense() {
if (state == SOLD) {
//我们正在"售出糖果"状态
System.out.println("一个糖果将从这里出来....");
count = count - 1;
//我们在这里处理"糖果售完"的情况
if (count == 0) {//最后一颗,将机器设置到"糖果售完"状态
System.out.println("库存为零!");
state = SOLD_OUT;
} else { //否则回到"没有25分钱"的状态
state = NO_QUARTER;
}
} else if (state == NO_QUARTER) { //以下都不应该发生,但如果顾客这么做了,得到的应该是错误消息而不是糖果
System.out.println("你需要向糖果机里投钱。。");
} else if (state == SOLD_OUT) {
System.out.println("糖果已经卖没了");
} else if (state == HAS_QUARTER) {
System.out.println("请您稍等交易还没有结束。");
}
}
}
测试就来自已写吧,我提供个思路,就是页面提供几个开关,即按纽、checkbox等在它们的单击事件上GumballMachine实例的内部状态改变。然后看其变化,就可以了。
大家看没看出来,这段代码还有一些“怪的味道”呀,这时如果业务变化了,如果客户是一个中奖的用户,需要糖果机吐出两块糖果,怎么办?,是不是还得在各个方法中把这个状态给加上呀,又得加一个if语句呢,这是一个业务发生了变化,如果业务要无限的变化下去,程序员是不是都要疯了,哈哈。所以要对其进行重构了。
要把这几个状态抽象出来。想到这里看一下代码就明白了。
public interface State {
//投钱的状态
public void insertQuarter();
//退钱的状态
public void ejectQuarter();
//按下按纽状态
public void turnCrank();
//发放物品状态
public void dispense();
}
下面是几个实现这个状态接口的实现类。
public class HasQuarterState implements State{
GumballMachineTwo gumballMachine;
//增加一个随机数产生器,产生10%的机会
Random randomWinner = new Random(System.currentTimeMillis());
public HasQuarterState(GumballMachineTwo gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() { //这是一个对当前状态不恰当的动作
System.out.println("不能再投钱了,已经有钱了。");
}
public void ejectQuarter() { //退钱并转换状态到NoQuarterState
System.out.println("退钱返回");
//把糖果机从有钱状态改成没钱状态
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
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 class NoQuarterState implements State {
GumballMachineTwo gumballMachine;
// 通过构造器得到糖果机的引用
public NoQuarterState(GumballMachineTwo gumballMachine) {
this.gumballMachine = gumballMachine;
}
// 分发物品
public void dispense() {
System.out.println("没有钱,不能分发糖果");
}
// 退钱
public void ejectQuarter() {
System.out.println("没有钱,不能退钱");
}
// 投钱
public void insertQuarter() {
// TODO Auto-generated method stub
}
// 按纽操作
public void turnCrank() {
// TODO Auto-generated method stub
}
}
public class SoldOutState implements State {
GumballMachineTwo gumballMachine;
public SoldOutState(GumballMachineTwo gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void dispense() {
System.out.println("糖果已经卖没了");
}
public void ejectQuarter() {
System.out.println("对不起,糖果已经卖完不能退钱");
}
public void insertQuarter() {
System.out.println("糖果已经卖完,不能再向里投钱了");
}
public void turnCrank() {
// TODO Auto-generated method stub
}
}
public class SoldState implements State{
GumballMachineTwo gumballMachine;
public SoldState(GumballMachineTwo gumballMachine) {
this.gumballMachine = gumballMachine;
}
//以下3个方法对此状态来说都是不恰当的
public void insertQuarter() {
System.out.println("已向你卖出一个糖果,请稍等,再向里投钱。");
}
public void ejectQuarter() {
System.out.println("对不起,糖果已经卖出不能退钱");
}
public void turnCrank() {
System.out.println("糖果已经卖出,不能再给你了");
}
//首先让机器发放糖果
public void dispense() {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("Oops, out of gumballs!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
public class WinnerState implements State{
GumballMachineTwo gumballMachine;
//下面都跟SoldState方法一样
public WinnerState(GumballMachineTwo gumballMachine) {
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
System.out.println("Please wait, we're already giving you a Gumball");
}
public void ejectQuarter() {
System.out.println("Please wait, we're already giving you a Gumball");
}
public void turnCrank() {
System.out.println("Turning again doesn't get you another gumball!");
}
//我们在这里发放出2颗糖果,然后进入NoQuarterState或SoldState
public void dispense() {
System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");
gumballMachine.releaseBall();
if (gumballMachine.getCount() == 0) {
gumballMachine.setState(gumballMachine.getSoldOutState());
} else {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("Oops, out of gumballs!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
}
下面是新的糖果类:
public class GumballMachineTwo {
//所有的状态都在这里
State soldOutState;
State noQuarterState;
State hasQuarterState;
State soldState;
State winnerState;//十次抽中一次的游戏,新的状态
//以及实例变量state
State state = soldOutState;
int count = 0;//记录糖果数量
public GumballMachineTwo(int numberGumballs) {
soldOutState = new SoldOutState(this); //每一种状态也都创建一个状态实例
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
this.count = numberGumballs;
if (numberGumballs > 0) { //如果超过0颗糖果,状态设为noQuarterState
state = noQuarterState;
}
}
//委托给当前状态
public void insertQuarter() {
state.insertQuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
//dispense()是一个内部动作方法,用户不可以直接要求机器发放糖果
public void turnCrank() {
state.turnCrank();
state.dispense();
}
//允许其他的对象将机器状态转换到不同的状态
void setState(State state) {
this.state = state;
}
//辅助方法释放出糖果,并将count实例变量值减1
void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if (count != 0) {
count = count - 1;
}
}
int getCount() {
return count;
}
void refill(int count) {
this.count = count;
state = noQuarterState;
}
public State getState() {return state;}
public State getSoldOutState() {return soldOutState;}
public State getNoQuarterState() {return noQuarterState;}
public State getHasQuarterState() {return hasQuarterState;}
public State getSoldState() {return soldState;}
public State getWinnerState() {return winnerState;}
}