动机(Motivattion)
在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生改变,比如电梯在运行和停止状态可以进行哪些操作,其支持的行为和运行/停止状态支持的行为就可能完全不同。
如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?
意图(Intent)
允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。
结构(Structure)
-
State:抽象状态角色 负责对象状态定义,并且封装环境角色以实现状态的切换
-
ConcreteState:具体状态角色 每个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理
- Context:环境角色
定义客户端需要的接口,并且负责具体状态的切换,串联各个状态的过渡。
State模式的几个要点
-
State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。
-
为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——即要么彻底转换,要么不转换。
- 如果State对象没有实例变量,那么各个上下文可以共享同一个State对象,从而节省对象开销。
某一角色在在执行行为时,通过环境角色知道自己目前的状态,然后执行此状态下的行为或通过状态下的过渡方法转到其他状态。
实例代码
抽象状态角色:
public abstract class State{
//定义一个环境角色,提供在子类访问
protected Context context;
//设置环境角色
public void setContext(Context context){
this.context = context;
}
//行为1
public abstract void handle1();
//行为2
public abstract void handle2();
}
具体状态角色:
public class ConcreteState1 extends State{
public void handle1(){
//本状态下必须处理的逻辑
}
public void handle2(){
//设置当前状态为state2
super.context.setState(Context.STATE2);
//过渡到state2状态,由handle2();
}
}
public class ConcreteState2 extends State{
public void handle1(){
//设置当前状态为state1
super.context.setState(Context.STATE1);
//过渡到state1状态,由handle1();
}
public void handle2(){
//本状态下必须处理的逻辑
}
}
具体环境角色:
public class Context{
//定义状态
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState2();
//当前状态
private State CurrentState;
//获得当前状态
public State getCurrentState(){
return CurrentState;
}
//设置当前状态
public void setCurrentState(State currentState){
this.CurrentState = currentState;
//把当前状态通知给各实现类
this.CurrentState = setContext(this);
}
//行为委托
public void handle1(){
this.CurrentState.handle1();
}
public void handle2(){
this.CurrentState.handle2();
}
}
场景类:
public class Client{
public static void main(String[] args){
//定义环境角色
Context context = new Context();
//初始化状态
context.setCurrentState(new ConcreteState1);
//行为执行
context.handle1();
context.handle2();
}
}