在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
大话设计模式中程杰老师给出的定义是,状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单就没有必要使用“状态模式”了。
状态模式结构图如下:
结构图解析:
1、State,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为;
2、ConcreteState类,具体状态类,每一个子类实现一个与Context的一个状态相关的行为;
3、Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态;
下面给出一个运动员开始和结束运动的实例还具体看一下状态模式的运用,类图如下:
package com.exercise.state;
/**
* 抽象状态接口
* @author lmb
*
*/
public interface State {
public void doAction(Context context);
}
package com.exercise.state;
/**
* 状态对象StartState
* @author lmb
*
*/
public class StartState implements State {
@Override
public void doAction(Context context) {
System.out.println("Player is in start state.");
context.setState(this);
}
public String toString(){
return "start state";
}
}
package com.exercise.state;
/**
* 状态对象StopState
* @author lmb
*
*/
public class StopState implements State {
@Override
public void doAction(Context context) {
System.out.println("Player is in stop state.");
context.setState(this);
}
public String toString(){
return "stop state";
}
}
package com.exercise.state;
/**
* 行为随着状态对象改变而改变的Context类
* @author lmb
*
*/
public class Context {
public State state;
public Context(){
state = null;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}
package com.exercise.state;
public class TestState {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);//将状态设定为开始状态
System.out.println(context.getState().toString());
StopState stopState = new StopState();
stopState.doAction(context);//将状态设定为结束状态
System.out.println(context.getState().toString());
}
}
运行结果:
Player is in start state.
start state
Player is in stop state.
stop state
状态模式的好处:
将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。简而言之就是,将特定状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个State实现类中,所以通过定义新的子类可以很容易的增加新的状态和转换。这样做的目的就是为了消除庞大的分支语句,大的分支判断通过会使得它们难以修改和扩展。状态模式通过把各种状态转移逻辑分不到State子类之间,来减少相互间的依赖,这样就容易维护和扩展了。
使用场景:
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。
缺点:
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对”开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。