在開發(fā)過程中,我們經(jīng)常會(huì)遇到很多if-else的判斷恒削,有的會(huì)有很多層吠架,當(dāng)然也不是說所有的涉及到if-else判斷的都要用該模式凡涩,但是提供了一個(gè)思路讓我們把代碼寫的更加的可擴(kuò)展,可維護(hù)豌鸡,按照對(duì)擴(kuò)展開發(fā)嘿般,對(duì)修改關(guān)閉的設(shè)計(jì)原則段标,可以很好的方便以后代碼的維護(hù)。
狀態(tài)模式封裝基于狀態(tài)的行為博个,并且將該行為委托到當(dāng)前狀態(tài)怀樟。
首先我們看一個(gè)案例:
以我們在商場或者小店旁邊經(jīng)常看到的糖果機(jī)器為例盆佣,當(dāng)投入一塊錢往堡,轉(zhuǎn)動(dòng)手柄,糖果機(jī)售出糖果共耍,如果糖果機(jī)器里有糖果虑灰,則發(fā)放糖果,糖果數(shù)據(jù)減少一顆痹兜,如果沒有一塊錢要求投入一塊錢穆咐,如果旋轉(zhuǎn)退回一塊錢,則退回一塊錢字旭;
這里邊涉及到了幾個(gè)狀態(tài):
1:有一塊錢
2:沒有一塊錢
3:售出糖果
4:糖果賣完了
運(yùn)用狀態(tài)模式我們該如何解決該問題呢对湃?
讓我們先來看一下狀態(tài)模式的定義:允許對(duì)象在內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來好像修改了它的類遗淳。
概念看起來總是抽象的拍柒,對(duì)象怎么在內(nèi)部狀態(tài)改變時(shí)改變它的行為,這就需要我們?nèi)ソ鉀Q實(shí)現(xiàn)屈暗。
廢話不多說拆讯,我們來看一下狀態(tài)模式的模型:
Context上下文類:可以擁有一些內(nèi)部狀態(tài)
State:定義一個(gè)所有具體狀態(tài)的共同接口,任何狀態(tài)都實(shí)現(xiàn)這個(gè)相同接口
ConcreteSateA:具體狀態(tài)养叛,處理來自context的請求种呐,每一個(gè)具體狀態(tài)都提供了它自己對(duì)于請求的實(shí)現(xiàn),所以當(dāng)context改變狀態(tài)時(shí)候行為也跟著改變弃甥。
接著我們來實(shí)現(xiàn):此處的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;
}
}
//狀態(tài)接口
public interfaceState {
public voidinsertQuarter();
public voidejectQuarter();
public voidturnCrank();
public voiddispense();
//具體狀態(tài)類
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 ";
}
}
以上就是具體的狀態(tài)模式的實(shí)現(xiàn)爽室,也許會(huì)有人說很麻煩,覺得本來可以用if-else或者switch一段代碼解決的問題潘飘,卻增加了這么多的類肮之;狀態(tài)模式確實(shí)會(huì)增加很多類,有幾個(gè)狀態(tài)就會(huì)有幾個(gè)具體的狀態(tài)類卜录,之所以這樣做是為了后期的擴(kuò)展以及維護(hù)戈擒,假如在A類中寫了一堆if-else如果多一個(gè)狀態(tài)就要多追加一個(gè)if-else判斷,也許有人覺得多加一個(gè)if-else判斷也沒什么艰毒,但是如果這里邊有不同的操作或者說在某個(gè)狀態(tài)時(shí)候做一些特殊的操作筐高,if-else判斷就會(huì)很麻煩,且違反了我們的類對(duì)修改關(guān)閉,對(duì)擴(kuò)展開放的涉及原則柑土。
狀態(tài)模式和策略模式比較像蜀肘,但他們的目的不同,策略模式通常會(huì)用行為或者算法來配置context類稽屏,狀態(tài)模式允許Context隨著狀態(tài)的改變而改變行為扮宠。