糖果机
假设有一个糖果机,每执行一个动作(曲线上的文字)会进入到不同的状态(圆圈中的文字),如下图所示:
根据上面的状态转换图,可以实现糖果机了:
public class GumballMachine{ // 四个状态 final static int SOLD_OUT = 0; // 糖果售罄 final static int NO_QUARTER = 1; // 没有25分钱 final static int HAS_QUARTER = 2; // 有25分钱 final static int SOLD = 3; // 正在售出糖果 int state = SOLD_OUT; // 当前状态(一开始糖果机没有糖果) int count = 0; // 机器中的糖果数 public GumballMachine(int count){ this.count = count; // 如果有库存,糖果机就开始进入到没有25分钱的状态(即开始等别人投钱) if(count > 0){ state = NO_QUARTER; } } // 当有25分钱投入机器后 public void insertQuarter(){ // 当前状态为投了25分钱 if(state == HAS_QUARTER){ // 告诉顾客不能再投 } // 当前状态为没投25分钱 else if(state == NO_QUARTER){ state = HAS_QUARTER; // 修改状态为有25分钱 // 告诉顾客现在成功投入25分钱 } // 当前状态为糖果售罄 else if(state == SOLD_OUT){ // 告诉顾客现在没糖果卖了 } // 当前状态为正在售出糖果 else if(state == SOLD){ // 告诉顾客正在出货 } } // 当顾客尝试退回25分钱 public void ejectQuarter(){ ... } // 当顾客尝试转动曲柄 public void turnCrank(){ ... } // 当机器开始弹出糖果 public void dispense(){ ... } }
上述代码已经很完整了,但假设加入新功能,比如在曲柄转动时有一定机率弹出两个糖果,该如何实现?
状态模式
允许对象(糖果机)在内部状态改变时改变它的行为,对象看起啦好像修改了它的类
定义状态接口和类
在原代码中可以看出,每个状态都对应的相同的四个动作(
insertQuarter
、ejectQuarter
、turnCrank
、dispense
),不如定义一个State
接口,让每个状态都去实现该接口,以没有25分钱状态为例
public interface State{
public void insertQuarter();
public void ejectQuarter();
public void turnCrank();
public void dispense();
}
// 当前状态为没有25分钱
public class NoQuarterState implements State{
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine){
this.gumballMachine = gumballMachine;
}
public void insertQuarter(){
// 打印机器接收了25分钱
gumballMachine.setState(gumballMachine.getHasQuarterState()); // 修改机器状态
}
public void ejectQuarter(){
// 打印都没给钱,不能要求退钱
}
public void turnCrank(){
// 打印都没给钱,不能转动曲柄
}
public void dispense(){
// 打印都没给钱,不能给糖果
}
}
改造糖果机
不使用静态整数代表状态,改为使用
State
对象表示
public class GumballMachine{
// 四个状态(可以继续加入赢家状态)
State soldOutState; // 糖果售罄
State noQuarterState = 1; // 没有25分钱
State hasQuarterState = 2; // 有25分钱
State soldState = 3; // 正在售出糖果
State state = soldOutState; // 当前状态(一开始糖果机没有糖果)
int count = 0; // 机器中的糖果数
public GumballMachine(int count){
soldOutState = new soldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
if(count > 0){
state = noQuarterState;
}
}
// *下面行为委托当前的状态对象即可
// 当有25分钱投入机器后
public void insertQuarter(){
state.insertQuarter();
}
// 当顾客尝试退回25分钱
public void ejectQuarter(){
state.ejectQuarter();
}
// 当顾客尝试转动曲柄
public void turnCrank(){
state.turnCrank();
state.dispense();
}
// 用于释放糖果
public void releaseBall(){
if(count != 0){
count = count - 1;
}
}
// 对于四个状态和当前状态的getter方法,此处省略
}
展示糖果机
public class GumballMachineTest{
public static void main(String[] args){
GumballMachine gumballMachine = new GumballMachine(10);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
...
}
}
已学模式
模式 | 描述 |
---|---|
状态模式 | 封装基于状态的行为,将行为委托到当前状态 |
模板模式 | 由子类决定如何实现算法中的某些步骤 |