在开发过程中,我们经常会遇到很多if-else的判断,有的会有很多层,当然也不是说所有的涉及到if-else判断的都要用该模式,但是提供了一个思路让我们把代码写的更加的可扩展,可维护,按照对扩展开发,对修改关闭的设计原则,可以很好的方便以后代码的维护。
状态模式封装基于状态的行为,并且将该行为委托到当前状态。
首先我们看一个案例:
以我们在商场或者小店旁边经常看到的糖果机器为例,当投入一块钱,转动手柄,糖果机售出糖果,如果糖果机器里有糖果,则发放糖果,糖果数据减少一颗,如果没有一块钱要求投入一块钱,如果旋转退回一块钱,则退回一块钱;
这里边涉及到了几个状态:
1:有一块钱
2:没有一块钱
3:售出糖果
4:糖果卖完了
运用状态模式我们该如何解决该问题呢?
让我们先来看一下状态模式的定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
概念看起来总是抽象的,对象怎么在内部状态改变时改变它的行为,这就需要我们去解决实现。
废话不多说,我们来看一下状态模式的模型:
Context上下文类:可以拥有一些内部状态
State:定义一个所有具体状态的共同接口,任何状态都实现这个相同接口
ConcreteSateA:具体状态,处理来自context的请求,每一个具体状态都提供了它自己对于请求的实现,所以当context改变状态时候行为也跟着改变。
接着我们来实现:此处的GumballMachineReuniform就是Context
public classGumballMachineReuniform {
StatesoldOutState;
StatenoQuarterState;
StatehasQuarterState;
StatesoldState;
StatewinnerState;
StatecurrentState=soldOutState;
//this variable shows how many candy in this machine
intcount=0;
publicGumballMachineReuniform(intnumberOfGumball){
soldOutState=newSoldOutState(this);
noQuarterState=newNoQuarterState(this);
hasQuarterState=newHasQuarterState(this);
soldState=newSoldState(this);
winnerState=newWinnerState(this);
this.count= numberOfGumball;
if(count>0) {
currentState=noQuarterState;
}
}
public voidinsertQuarter() {
currentState.insertQuarter();
}
public voidejectQuarter() {
currentState.ejectQuarter();
}
public voidturnCrank() {
currentState.turnCrank();
currentState.dispense();
}
public voidsetState(State state) {
this.currentState= state;
}
//reinforce to release ball
public voidreleaseBall() {
System.out.println("A gumball comes rolling out the slot .... ");
if(count!=0) {
count=count-1;
}
}
publicState getSoldOutState() {
returnsoldOutState;
}
public voidsetSoldOutState(State soldOutState) {
this.soldOutState= soldOutState;
}
publicState getNoQuarterState() {
returnnoQuarterState;
}
public voidsetNoQuarterState(State noQuarterState) {
this.noQuarterState= noQuarterState;
}
publicState getHasQuarterState() {
returnhasQuarterState;
}
public voidsetHasQuarterState(State hasQuarterState) {
this.hasQuarterState= hasQuarterState;
}
publicState getSoldState() {
returnsoldState;
}
public voidsetSoldState(State soldState) {
this.soldState= soldState;
}
public intgetCount() {
returncount;
}
public voidsetCount(intcount) {
this.count= count;
}
publicState getWinnerState() {
returnwinnerState;
}
public voidsetWinnerState(State winnerState) {
this.winnerState= winnerState;
}
@Override
publicString toString() {
returncount+" gumball ";
}
publicState getState() {
returncurrentState;
}
}
//状态接口
public interfaceState {
public voidinsertQuarter();
public voidejectQuarter();
public voidturnCrank();
public voiddispense();
//具体状态类
public classSoldStateimplementsState {
GumballMachineReuniformgumballMachineReuniform;
publicSoldState(GumballMachineReuniform gumballMachineReuniform){
this.gumballMachineReuniform= gumballMachineReuniform;
}
@Override
public voidinsertQuarter() {
System.out.println("You can't insert another coin ,please wait machine give u a gumball");
}
@Override
public voidejectQuarter() {
System.out.println("sorry,you have turned the crank .");
}
@Override
public voidturnCrank() {
System.out.println("You can't turn crank twice ");
}
@Override
public voiddispense() {
gumballMachineReuniform.releaseBall();
if(gumballMachineReuniform.getCount() >0) {
gumballMachineReuniform.setState(gumballMachineReuniform.getNoQuarterState());
}else{
System.out.println("Oops out of gumball !");
gumballMachineReuniform.setState(gumballMachineReuniform.getSoldOutState());
}
}
@Override
publicString toString() {
return" solding state ";
}
}
public classSoldOutStateimplementsState {
GumballMachineReuniformgumballMachine;
publicSoldOutState(GumballMachineReuniform gumballMachineReuniform) {
this.gumballMachine= gumballMachineReuniform;
}
@Override
public voidinsertQuarter() {
System.out.println("gumball has been sold out ");
}
@Override
public voidejectQuarter() {
System.out.println("can not eject quarter ");
}
@Override
public voidturnCrank() {
System.out.println("can not turn crank sold out gumball ");
}
@Override
public voiddispense() {
System.out.println("can not dispense crank sold out ");
}
@Override
publicString toString() {
return" already sold out ";
}
}
public classNoQuarterStateimplementsState {
GumballMachineReuniformgumballMachine;
publicNoQuarterState(GumballMachineReuniform gumballMachine){
this.gumballMachine= gumballMachine;
}
@Override
public voidinsertQuarter() {
System.out.println("you have insert one coin !!");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public voidejectQuarter() {
System.out.println("you haven't insert one coin please insert coin first!");
}
@Override
public voidturnCrank() {
System.out.println("you have turned but there's no quarter insert !");
}
@Override
public voiddispense() {
System.out.println("You need to pay first ");
}
@Override
publicString toString() {
return"waiting to insert coin ";
}
}
public classHasQuarterStateimplementsState {
RandomrandomWinner=newRandom(System.currentTimeMillis());
GumballMachineReuniformgumballMachine;
publicHasQuarterState(GumballMachineReuniform gumballMachine) {
this.gumballMachine= gumballMachine;
}
@Override
public voidinsertQuarter() {
System.out.println("You can't insert another coin ");
}
@Override
public voidejectQuarter() {
System.out.println("Quarter returned !");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public voidturnCrank() {
System.out.println("You turned...");
intwinner =randomWinner.nextInt(10);
if((winner ==0) && (gumballMachine.getCount() >1)) {
gumballMachine.setState(gumballMachine.getWinnerState());
}else{
gumballMachine.setState(gumballMachine.getSoldState());
}
}
@Override
public voiddispense() {
System.out.println("No gumball dispense ");
}
@Override
publicString toString() {
return"has quarter ";
}
}
以上就是具体的状态模式的实现,也许会有人说很麻烦,觉得本来可以用if-else或者switch一段代码解决的问题,却增加了这么多的类;状态模式确实会增加很多类,有几个状态就会有几个具体的状态类,之所以这样做是为了后期的扩展以及维护,假如在A类中写了一堆if-else如果多一个状态就要多追加一个if-else判断,也许有人觉得多加一个if-else判断也没什么,但是如果这里边有不同的操作或者说在某个状态时候做一些特殊的操作,if-else判断就会很麻烦,且违反了我们的类对修改关闭,对扩展开放的涉及原则。
状态模式和策略模式比较像,但他们的目的不同,策略模式通常会用行为或者算法来配置context类,状态模式允许Context随着状态的改变而改变行为。