状态模式的核心是将状态抽象为类,然后将状态的改变包含在类中,这样就避免了在client中写出大量的if...else的判断。同时符合了设计原则中的开闭原则。状态模式往往应用的场景是模式非常复杂的场景,比如状态之间的转换非常繁杂。状态模式的升级实际就是状态机,我们在之后会进行更详细的讨论。
状态模式的类图如下:
context为上下文,实际可以理解为一个封装,封装了状态,这样就状态就对外不可见。同时状态类可以改变context上下文的状态,从而改变其行为。而状态之间的转换关系也被封装在了状态对象内部。
我们以设计模式之禅中所举的电梯的例子来进行介绍:
对于电梯来讲,具有open,close,run,stop这几个动作,而对于状态来讲,有OPENING_STATE, CLOSING_STATE, RUNNING_STATE, STOPPING_STATE这几个状态,状态之间的装换关系满足一下的表格:
open | close | run | stop | |
---|---|---|---|---|
OPENING_STATE | ?? | |||
CLOSING_STATE | ?? | ?? | ?? | |
RUNNING_STATE | ?? | |||
STOPPING_STATE | ?? | ?? |
代码如下:
public class Context {
//定义出所有的电梯状态
public final static OpenningState openningState = new OpenningState();
public final static ClosingState closeingState = new ClosingState();
public final static RunningState runningState = new RunningState();
public final static StoppingState stoppingState = new StoppingState();
//定一个当前电梯状态
private LiftState liftState;
public LiftState getLiftState() {
return liftState;
}
public void setLiftState(LiftState liftState) {
this.liftState = liftState;
//把当前的环境通知到各个实现类中
this.liftState.setContext(this);
}
public void open(){
this.liftState.open();
}
public void close(){
this.liftState.close();
}
public void run(){
this.liftState.run();
}
public void stop(){
this.liftState.stop();
}
}
public abstract class LiftState {
protected Context context;
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public abstract void open();
public abstract void close();
public abstract void run();
public abstract void stop();
}
public class ClosingState extends LiftState {
@Override
public void close() {
System.out.println("电梯门关闭...");
}
@Override
public void open() {
super.context.setLiftState(Context.openningState); //置为门敞状态
super.context.getLiftState().open();
}
@Override
public void run() {
super.context.setLiftState(Context.runningState); //设置为运行状态;
super.context.getLiftState().run();
}
@Override
public void stop() {
super.context.setLiftState(Context.stoppingState); //设置为停止状态;
super.context.getLiftState().stop();
}
}
public class OpenningState extends LiftState {
@Override
public void open() {
System.out.println("电梯门开启...");
}
@Override
public void close() {
//状态修改
super.context.setLiftState(Context.openningState);
//动作委托为CloseState来执行
super.context.getLiftState().close();
}
@Override
public void run() {
}
@Override
public void stop() {
}
}
public class RunningState extends LiftState {
@Override
public void open() {
}
@Override
public void close() {
}
@Override
public void run() {
System.out.println("电梯上下跑...");
}
@Override
public void stop() {
super.context.setLiftState(Context.stoppingState); //环境设置为停止状态;
super.context.getLiftState().stop();
}
}
public class StoppingState extends LiftState {
@Override
public void open() {
super.context.setLiftState(Context.openningState);
super.context.getLiftState().open();
}
@Override
public void close() {
}
@Override
public void run() {
super.context.setLiftState(Context.runningState);
super.context.getLiftState().run();
}
@Override
public void stop() {
System.out.println("电梯停止了...");
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setLiftState(new ClosingState());
context.open();
context.close();
context.run();
context.stop();
}
}