定义
状态模式允许对象在内部状态改变时改变它的行为, 对象看起来好像修改了它的类
- 这个模式将状态封装成独立的类, 并将动作委托到当前代表的对象
- 当状态流转是固定的时候, 就适合放在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;}@Overridepublic void insertCoin() {System.out.println("有硬币了, 请转动曲柄!");machine.setState(machine.getHasCoinState());}@Overridepublic void ejectCoin() {System.out.println("没有硬币, 无法退!");}@Overridepublic void turnCrack() {System.out.println("没有硬币, 不能转曲柄!");}@Overridepublic void dispense() {System.out.println("请投币!");}}
HasCoinState, 在转动曲柄动作中改变machine的状态
public class HasCoinState implements State {Machine machine;public HasCoinState(Machine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("已经有硬币了, 别投了!");}@Overridepublic void ejectCoin() {System.out.println("退出硬币!");machine.setState(machine.getNoCoinState());}@Overridepublic void turnCrack() {System.out.println("转动曲柄!");machine.setState(machine.getHasGumballState());}@Overridepublic void dispense() {System.out.println("请转曲柄!");}}
HasGumballState, 在发糖动作中调用machine的方法, 并获取糖果数量来改变machine的状态
public class HasGumballState implements State {Machine machine;public HasGumballState(Machine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("再投没用!");}@Overridepublic void ejectCoin() {System.out.println("已转曲柄!不能退!");}@Overridepublic void turnCrack() {System.out.println("已转了一次!请稍等!");}@Overridepublic 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;}@Overridepublic void insertCoin() {System.out.println("没有糖果了, 投币也没用!");}@Overridepublic void ejectCoin() {System.out.println("无法退币!");}@Overridepublic void turnCrack() {System.out.println("没有糖果了, 转也没有用!");}@Overridepublic void dispense() {System.out.println("发放失败!没有糖果了!");}}
这样设计的好处:
1.让每个状态的行为局部化到他自己的类中;
2.对修改关闭, 对拓展开放;
3.更易阅读和理解
