现在的面向对象软件开发过程中,对象便是核心。而对象在不同的情况下会表现出不同的行为,这便是状态。我们也许会用一堆 if-else 判断,或者 switch-case 状态机,但在复杂的状态情况下,状态模式应运而生。
状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
结构类图如下
上图中包括:
1、环境类(Context): 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
2、抽象状态类(AbstractState): 定义一个接口以封装与Context的一个特定状态相关的行为。
3、具体状态类(ConcreteState): 每一子类实现一个与Context的一个状态相关的行为。
下面看个例子:假设现在有一个开关,控制三种颜色的切换,blue,green,red,蓝色下一个绿色,绿色下一个红色,红色下一个是蓝色,也可以倒过来。
首先是抽象状态类
/* * 抽象状态类,执行上一个下一个的操作,还可以获得当前的状态 * 当然在这可以既执行别的操作,比如开关拨到某个颜色的时候,颜色对应的灯亮 */ public interface State { public void last(Context c); public void next(Context c); public String getState(); }
其次是具体状态类
/* * 蓝色状态类,实现的接口的方法,通过状态管理器在上一个或者下一个方法中 * 设置改变后的状态 */ public class BlueState implements State { public String getState() { // TODO Auto-generated method stub return "blue"; } public void last(Context c) { c.setState(new GreenState()); } public void next(Context c) { c.setState(new RedState()); } } /* * 绿色状态类,实现的接口的方法,通过状态管理器在上一个或者下一个方法中 * 设置改变后的状态 */ public class GreenState implements State { public String getState() { return "green"; } public void last(Context c) { c.setState(new RedState()); } public void next(Context c) { c.setState(new BlueState()); } } /* * 红色状态类,实现的接口的方法,通过状态管理器在上一个或者下一个方法中 * 设置改变后的状态 */ public class RedState implements State { public String getState() { return "red"; } public void last(Context c) { c.setState(new BlueState()); } public void next(Context c) { c.setState(new GreenState()); }
最后是环境类
/* * 环境类,设置初始状态,得到当前状态, * 提供了两个操作,上一个的操作方法中,调用了当前状态的last方法,将状态管理器的状态更新 * 下一个的操作方法中,调用了当前状态的next方法,将状态管理器的状态更新 */ public class Context { private State state = null; public State getState() { return state; } public void setState(State state) { this.state = state; } public void push(){ state.last(this); System.out.println(state.getState()); } public void pull(){ state.next(this); System.out.println(state.getState()); } }
测试类
/* * 测试类 */ public class Client{ public static void main(String[] args) throws InterruptedException { /* * 创建一个状态管理器,设置初始状态为红色, * 然后就可以执行状态管理器的last或者next方法 */ Context c = new Context(); State redsState = new RedState(); c.setState(redsState); while (true){ System.out.println("当前状态:"+c.getState().getState()); System.out.print("上一个状态: "); c.push(); Thread.currentThread().sleep(2000); } } }
结果为
从上面的例子可以看出一些状态模式的优缺点:
优点:
1、它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
2、它使得状态转换显式化。
3、State对象可被共享。
缺点:
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
总结:状态模式的主要优点在于封装了转换规则,并枚举可能的状态,它将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为,还可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;其缺点在于使用状态模式会增加系统类和对象的个数,且状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,对于可以切换状态的状态模式不满足“开闭原则”的要求。