当我们希望使用一个系统,而不希望知晓系统的操作细节时,可以使用状态模式。
状态模式把系统看作一个自动机,通过各种状态之间的转移来自动运行。状态被视为接口或是抽象类,具体的状态通过实现或者继承的方式来规定状态转移规则(大多数时候使用接口)。用户只需向机器提供输入和请求,机器就能自动实现相应状态的跳转并返回对应的结果。
以糖果机为例。购买糖果的大体流程如下:
对应上述五个动作,实际有四个状态:
因此可以定义一个State接口,封装上述五个动作,然后由四个子类分别实现四个状态中对应每个动作的具体操作。
package state;
public interface State {
public void insertQuarter();
public void ejectQuarter();
public void turnCrank();
public void dispense();
public void refill();
}
package state;
public class NoQuarterState implements State {
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You inserted a quarter");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
System.out.println("You haven‘t inserted a quarter");
}
@Override
public void turnCrank() {
System.out.println("You turned, but there‘s no quarter");
}
@Override
public void dispense() {
System.out.println("You need tp pay first");
}
@Override
public void refill() {
System.out.println("Sorry, gumballs are not sold out");
}
}
package state;
public class GumballMachine {
State soldOutState;
State noQuarterState;
State hasQuarterState;
State soldState;
State winnerState;
State state = soldState;
int count = 0;
public GumballMachine(int numberGumballs) {
soldOutState = new SoldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
winnerState = new WinnerState(this);
this.count = numberGumballs;
if (numberGumballs > 0) {
state = noQuarterState;
} else {
state = soldOutState;
}
}
public void insertQuarter() {
state.insertQuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
public void turnCrank() {
state.turnCrank();
state.dispense();
}
public void refill() {
state.refill();
}
void setState(State state) {
this.state = state;
}
void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if (count != 0) {
count--;
}
}
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;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public String toString() {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("Mighty Gumball, Inc.\n");
stringBuffer.append("Java-enabled Standing Gumball Model #2004\n");
stringBuffer.append("Inventory: " + getCount() + " gumballs\n");
return stringBuffer.toString();
}
}
这里仅以其中一个状态为例,展示状态转移的代码模板。
可以看到,用户只能接触到自动机,而自动机的方法都是调用了其当前状态实例中的方法,因此用户不需要知道机器当前的状态,也可以进行机器目前允许的任何操作,并且能够期待机器返回当前状态与输入对应的正确的结果。
观察代码结构,可以发现状态模式与策略模式的类图是一样的,但两者的目的却截然不同。
策略模式将可以互换的行为封装起来,然后使用委托的方法,由用户决定使用哪一个行为,此时用户清楚地知道每个行为;而状态模式将可以互相转移的状态封装起来,并将行为委托到当前状态,此时用户不知道每个状态的行为,不知道状态之间如何转移,可以轻松地发出请求或提供输入。
原文:https://www.cnblogs.com/aries99c/p/12845635.html