定义
状态模式允许对象在内部状态改变时改变它的行为, 对象看起来好像修改了它的类
- 这个模式将状态封装成独立的类, 并将动作委托到当前代表的对象
- 当状态流转是固定的时候, 就适合放在context中; 当转换是更动态的时候, 通常放在状态类中
案例
背景
原来设计代码: 现在要增加一个状态, 这个类就需要大面积的更改, 不易拓展
/**
* Machine
*
* @author xinzhang
* @author Shenzhen Greatonce Co Ltd
* @version 2020/1/22
* 投入硬币-->转动曲柄-->分发糖果
*/
public class GumballMachine {
// 糖果机有四种状态, 有无硬币, 有硬币, 无糖果, 有糖果
private final int NO_COIN = 0;
private final int HAS_COIN = 1;
private final int NO_GUMBALL = 2;
private final int HAS_GUMBALL = 3;
private int state = NO_GUMBALL;
private int gumballNum;
public GumballMachine(int gumballNum) {
this.gumballNum = gumballNum;
if (gumballNum > 0) {
state = NO_COIN;
}
}
/**
* 投入硬币
*/
public void insertCoin() {
switch (state) {
case NO_COIN:
case HAS_GUMBALL:
System.out.println("有硬币了!请转动曲柄!");
state = HAS_COIN;
break;
case HAS_COIN:
System.out.println("有硬币了别再投了!");
break;
case NO_GUMBALL:
System.out.println("投也没用, 糖果售罄!");
break;
}
}
/**
* 退回硬币
*/
public void ejectCoin() {
switch (state) {
case NO_COIN:
System.out.println("请先投入硬币!");
break;
case NO_GUMBALL:
System.out.println("糖没了, 硬币也是不会退的!");
break;
case HAS_GUMBALL:
System.out.println("已经转动了曲柄, 不给退!");
break;
case HAS_COIN:
System.out.println("退回硬币!");
state = NO_COIN;
break;
}
}
/**
* 转动曲柄
*/
public void turnCrack() {
switch (state) {
case NO_COIN:
System.out.println("先投硬币才能转!");
break;
case HAS_COIN:
if (gumballNum > 0) {
state = HAS_GUMBALL;
} else {
state = NO_GUMBALL;
}
break;
case HAS_GUMBALL:
System.out.println("转过一次不能再转了!");
break;
case NO_GUMBALL:
System.out.println("没糖, 转也没用!");
break;
}
}
/**
* 发放糖果
*/
public void dispense() {
switch (state) {
case NO_COIN:
System.out.println("先付钱!");
break;
case HAS_COIN:
System.out.println("先转曲柄!");
break;
case NO_GUMBALL:
System.out.println("没有糖果了!");
break;
case HAS_GUMBALL:
gumballNum--;
if (gumballNum <= 0) {
System.out.println("现在没糖了!");
state = NO_GUMBALL;
} else {
System.out.println("发一个糖果!");
state = NO_COIN;
}
}
}
}
使用状态模式后:
Machine, 持有四种状态类(注意多态写法),构造方法中初始化, 作为外部调用的入口, 去调用状态的动作
public class Machine {
private State noCoinState;
private State hasCoinState;
private State noGumballState;
private State hasGumballState;
private State state = noGumballState;
private int count = 0;
public Machine(int count) {
noCoinState = new NoCoinState(this);
hasCoinState = new HasCoinState(this);
noGumballState = new NoGumballState(this);
hasGumballState = new HasGumballState(this);
this.count = count;
if (count > 0) {
state = noCoinState;
}
}
public void insertCoin() {
state.insertCoin();
}
public void ejectCoin() {
state.ejectCoin();
}
public void turnCrack() {
state.turnCrack();
}
public void dispense() {
state.dispense();
}
public void releaseGumball() {
System.out.println("释放一个糖果!");
if (count > 0) {
count--;
}
}
public State getNoCoinState() {
return noCoinState;
}
public State getHasCoinState() {
return hasCoinState;
}
public State getNoGumballState() {
return noGumballState;
}
public State getHasGumballState() {
return hasGumballState;
}
public void setHasCoinState(State hasCoinState) {
this.hasCoinState = hasCoinState;
}
public void setNoGumballState(State noGumballState) {
this.noGumballState = noGumballState;
}
public void setHasGumballState(State hasGumballState) {
this.hasGumballState = hasGumballState;
}
public void setNoCoinState(State noCoinState) {
this.noCoinState = noCoinState;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
State接口
public interface State {
void insertCoin();
void ejectCoin();
void turnCrack();
void dispense();
}
NoCoinState, 持有machine对象, 在投币动作中, 改变machine的状态
public class NoCoinState implements State {
Machine machine;
public NoCoinState(Machine machine) {
this.machine = machine;
}
@Override
public void insertCoin() {
System.out.println("有硬币了, 请转动曲柄!");
machine.setState(machine.getHasCoinState());
}
@Override
public void ejectCoin() {
System.out.println("没有硬币, 无法退!");
}
@Override
public void turnCrack() {
System.out.println("没有硬币, 不能转曲柄!");
}
@Override
public void dispense() {
System.out.println("请投币!");
}
}
HasCoinState, 在转动曲柄动作中改变machine的状态
public class HasCoinState implements State {
Machine machine;
public HasCoinState(Machine machine) {
this.machine = machine;
}
@Override
public void insertCoin() {
System.out.println("已经有硬币了, 别投了!");
}
@Override
public void ejectCoin() {
System.out.println("退出硬币!");
machine.setState(machine.getNoCoinState());
}
@Override
public void turnCrack() {
System.out.println("转动曲柄!");
machine.setState(machine.getHasGumballState());
}
@Override
public void dispense() {
System.out.println("请转曲柄!");
}
}
HasGumballState, 在发糖动作中调用machine的方法, 并获取糖果数量来改变machine的状态
public class HasGumballState implements State {
Machine machine;
public HasGumballState(Machine machine) {
this.machine = machine;
}
@Override
public void insertCoin() {
System.out.println("再投没用!");
}
@Override
public void ejectCoin() {
System.out.println("已转曲柄!不能退!");
}
@Override
public void turnCrack() {
System.out.println("已转了一次!请稍等!");
}
@Override
public void dispense() {
machine.releaseGumball();
if (machine.getCount() > 0) {
System.out.println("发糖!");
machine.setState(machine.getNoCoinState());
} else {
System.out.println("没糖了!");
machine.setState(machine.getNoGumballState());
}
}
}
NoGumballState
public class NoGumballState implements State {
Machine machine;
public NoGumballState(Machine machine) {
this.machine = machine;
}
@Override
public void insertCoin() {
System.out.println("没有糖果了, 投币也没用!");
}
@Override
public void ejectCoin() {
System.out.println("无法退币!");
}
@Override
public void turnCrack() {
System.out.println("没有糖果了, 转也没有用!");
}
@Override
public void dispense() {
System.out.println("发放失败!没有糖果了!");
}
}
这样设计的好处:
1.让每个状态的行为局部化到他自己的类中;
2.对修改关闭, 对拓展开放;
3.更易阅读和理解