允许一个对象在其内部状态改变时改变它的行为,这种改变看起来似乎是修改了它的类本身。就像进行TCP连接时,TCP连接的状态都会经过一系列的变化,当从一个状态变为另一个状态时,它的功能就可能发生变化。
状态模式适用于,一个对象的行为是由它的状态决定的,并且它必须在运行时刻根据状态改变它的行为,或者一些操作依赖于庞大的一系列的分支语句,而且这些分支依赖于该对象的状态。在使用状态模式时,Client会通过使用可用的State对象配置Context对象,之后Client会和这个配置后的Context对象江湖而不是与State对象交互。最后,当需要改变Context对象,并重新配置它时,Client才会再创建或者使用State对象配置Context对象。
public abstract class State {
public abstract void handle(Context context);
public static State instance(){
throw new RuntimeException("Can't instance!");
}
public void changeState(Context context, State state) {
context.changeState(state);
}
}
public class ConcreteStateA extends State {
private static State s = null;
@Override
public void handle(Context context) {
System.out.println("Handle the state(ConcreteStateA)!");
changeState(context, instance());
}
public static State instance() {
if (s == null) {
s = new ConcreteStateA();
}
return s;
}
}
public class ConcreteStateB extends State{
private static State s = null;
@Override
public void handle(Context context) {
System.out.println("Handle the state(ConcreteStateB)!");
changeState(context, instance());
}
public static State instance(){
if (s == null) {
s = new ConcreteStateB();
}
return s;
}
}
public class Context {
private State state = null;
public Context(State state) {
this.state = state;
}
public void changeState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
public class Client {
@Test
public void test() {
Context context = new Context(ConcreteStateA.instance());
context.request();
context.changeState(ConcreteStateB.instance());
context.request();
}
}
以上代码中State对象规定了默认的状态父类,它提供了一个可以改变传给它的Context对象的状态的方法,每个State子类将自身传给Context对象,从而将自己与Context对象绑定。Context对象可以接受State对象,并且可以在运行时由其他对象提供State对象,当需要向Context对象请求request方法时,它都会将请求导向State对象,由State对象进行真正的处理,这样就可以在运行时动态的设定request处理请求的方式了。值得一提的是这里的State对象使用了单例模式来创建和复用State对象。
以上的请求与处理方式就像是Context对象将与状态相关的请求委托给了ConcreteState对象来处理,这种方式将特定的状态与状态的行为局部化,并且将不同状态的行为分割开来,这样当需要新的处理方式时就可以通过增加新的状态和转移方式来增强现有代码的能力。同时,状态的状态转移逻辑不是由if或switch语句来控制的,而是由内部的State对象控制,分布在不同的State对象内部,这样提高了代码的可拓展性。