现在的面向对象软件开发过程中,对象便是核心。而对象在不同的情况下会表现出不同的行为,这便是状态。我们也许会用一堆 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、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
总结:状态模式的主要优点在于封装了转换规则,并枚举可能的状态,它将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为,还可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;其缺点在于使用状态模式会增加系统类和对象的个数,且状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,对于可以切换状态的状态模式不满足“开闭原则”的要求。