状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类
——将状态封装成独立的类,将动作委托给当前状态对象,所以行为会随着内部状态的变化而变化
状态转换图:为每一个状态创建一个实现一组相同操作接口的对象,实体对象包含所有状态并有一个当前状态接口的引用
特点:
- 允许一个对象基于不用的状态有不同的行为
- 把变化的东西取出来,局部化每个状态的行为,每个状态的行为局部化到自己的类中,遵守“封装变化”原则,减少了繁琐的if语句,满足“对修改关闭,对扩展开放”原则,便于阅读与理解
- 所有的状态实现共同的state接口,state接口可以作为抽象类,减少代码冗余,默认实现可以作为不支持操作
- 实体对象包含它的每一个状态,当前状态总是这些状态之一,当动作被调用时,它会把动作委派给当前的状态完成
注意:
- 状态的转换可以在Context中实现(状态转换是固定的),亦可在具体的状态类中实现(状态转化是动态的,状态类之间产生了依赖)
- 客户不可以直接改变Context中的状态
- 状态可以被共享
- 明确主机的行为与主机的状态的之间的关系,主机的某种状态的操作可以操作主机的行为。例:
状态模式vs策略模式:
- 均允许对象通过组合和委托拥有不同的行为或算法
- 状态模式的的当前状态游走于对象的状态集合之间,状态的改变是有方案的,客户不了解状态变化的方式;策略模式客户主动指定状态中的哪一个
举例:
实现糖果自动贩卖机过程,状态转换图如上
状态接口及SoldState实现:
1 public interface State { 2 public void insertQuarter(); // 投入25分钱 3 public void ejectQuarter(); // 拒绝25分钱 4 public void turnCrank(); // 转动曲柄 5 public void dispense(); // 发放糖果 6 } 7 8 9 public class SoldState implements State{ 10 11 GumballMachine gumballMachine; 12 public SoldState(GumballMachine gumballMachine) { 13 this.gumballMachine = gumballMachine; 14 } 15 // 投入25分钱 16 public void insertQuarter() { 17 System.out.println("Please wait, we're already giving you a gumball"); 18 } 19 // 拒绝25分钱 20 public void ejectQuarter() { 21 System.out.println("Sorry,you have already turn crank"); 22 } 23 // 转动曲柄 24 public void turnCrank() { 25 System.out.println("trun twice ,doesn't give you anthor gamball!"); 26 } 27 // 发放糖果 28 public void dispense() { 29 gumballMachine.releaseBall(); 30 if(gumballMachine.getCount()>0){ 31 gumballMachine.setState(gumballMachine.getNoQuarterState()); 32 } else { 33 System.out.println("Opps,out of gamball!"); 34 gumballMachine.setState(gumballMachine.getSoldOutState()); 35 } 36 } 37 }
自动贩卖机实现:
1 public class GumballMachine { 2 //状态实例 3 State soldOutState; 4 State noQuarterState; 5 State hasQuarterState; 6 State soldState; 7 State winnerState; 8 9 // 实例变量state,初始化为糖果售罄状态 10 State state = soldOutState; 11 // 记录机器内装有糖果的数目,开始机器是没有装糖果的 12 int count=0; 13 // 构造器取得糖果的初始数目并把它放在一个实例变量count中 14 public GumballMachine(int numberGumballs) { 15 // 每种状态都创建一个状态实例 16 soldOutState=new SoldOutState(this); 17 noQuarterState=new NoQuarterState(this); 18 hasQuarterState=new HasQuarterState(this); 19 soldState=new SoldState(this); 20 winnerState = new WinnerState(this); 21 22 this.count = numberGumballs; 23 // 若超过0颗糖果,就将状态设置为NoQuarterState 24 if(numberGumballs > 0) { 25 state = noQuarterState; 26 } 27 } 28 // 取得机器内的糖果数目 29 public int getCount() { 30 return count; 31 } 32 // 取得糖果售罄状态 33 // …… 34 35 // 投入25分钱 36 public void insertQuarter(){ 37 state.insertQuarter(); 38 } 39 // 拒绝25分钱 40 public void ejectQuarter(){ 41 state.ejectQuarter(); 42 } 43 // 转动曲柄 44 public void turnCrank(){ 45 state.turnCrank(); 46 state.dispense(); 47 } 48 // 设置状态 49 public void setState(State state){ 50 this.state=state; 51 } 52 // 糖果滚出来一个 53 public void releaseBall(){ 54 System.out.println("A gumball comes rolling out of the solt..."); 55 if(count!=0){ 56 count--; 57 } 58 } 59 }