
1.状态模式简介
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类;
当状态改变时,这个对象的行为也会变,而看起来就像是这个类改变了一样。
2.举例说明
案例:城市的纵向发展离不开电梯,就以电梯为例。
状态\动作 | 开门 | 关门 | 运行 | 停止 | 开门状态 | X | O | X | X | 关门状态 | O | X | O | O | 运行状态 | X | X | X | O | 停止状态 | O | X | O | X |
状态模式包含三个角
- Context:它就是那个含有状态的对象,它可以处理一些请求,这些请求最终产生的响应会与状态相关。
- State:状态接口,它定义了每一个状态的行为集合,这些行为会在Context中得以使用。
- ConcreteState:具体状态,实现相关行为的具体状态类。
下面我们已代码分别说明:
环境角色Context
/**
* 环境角色Context
*
* 首先定义出电梯的所有状态,然后定义当前电梯状态,
* 再定义四种状态对应的方法,如Openning状态是由open()方法产生的。
* 至于这些方法中的逻辑,就用print来代替了。
*/
public class A1_Context {
//定义出电梯的所有状态
public final static B1_LiftState OPENNING_STATE = new C1_OpenningState();
public final static B1_LiftState CLOSING_STATE = new C2_ClosingState();
public final static B1_LiftState RUNNING_STATE = new C3_RunningState();
public final static B1_LiftState STOPPING_STATE = new C4_StoppingState();
//定义一个当前电梯状态
private B1_LiftState liftState;
public B1_LiftState getLiftState() {
return liftState;
}
public void setLiftState(B1_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();
}
}
抽象电梯状态LiftState
/**
* 抽象电梯状态LiftState
*
* 这里我们定义并把Context这个环境角色聚合进来,并传递到子类。
* 所以我们可以这样理解,Context环境角色的作用就是串联各个状态的过渡,
* 也就是在4个具体的实现类中,各自根据自己的环境来决定如何进行状态的过渡。
*/
public abstract class B1_LiftState {
/**
* 持有环境角色Context
*/
protected A1_Context context;
public void setContext(A1_Context context) {
this.context = context;
}
//电梯门开启动作
public abstract void open();
//电梯门关闭动作
public abstract void close();
//电梯运行
public abstract void run();
//电梯停止
public abstract void stop();
}
电梯开门状态
/**
* 电梯开门状态
*/
public class C1_OpenningState extends B1_LiftState {
/**
* 执行打开电梯门方法
*/
@Override
public void open() {
System.out.println("电梯门开启");
}
/**
* 打开后还可以关闭电梯门
*/
@Override
public void close() {
//状态修改
super.context.setLiftState(A1_Context.CLOSING_STATE);
//动作委托为CLOSING_STATE执行
super.context.getLiftState().close();
}
/**
* 门开着不能运行
*/
@Override
public void run() {
//什么都不做
}
/**
* 门开着已经停止了(开门的时候门就是停止的)
*/
@Override
public void stop() {
//什么都不做
}
}
电梯闭门状态
/**
* 电梯闭门状态
*/
public class C2_ClosingState extends B1_LiftState {
/**
* 电梯门关了可以再开
*/
@Override
public void open() {
//置为开门状态
super.context.setLiftState(A1_Context.OPENNING_STATE);
super.context.getLiftState().open();
}
/**
* 执行电梯门关闭方法
*/
@Override
public void close() {
System.out.println("电梯门关闭");
}
/**
* 电梯门关了就可以运行
*/
@Override
public void run() {
super.context.setLiftState(A1_Context.RUNNING_STATE);
super.context.getLiftState().run();
}
/**
* 电梯门关了但没有按楼层
*/
@Override
public void stop() {
super.context.setLiftState(A1_Context.STOPPING_STATE);
super.context.getLiftState().stop();
}
}
电梯运行状态
/**
* 电梯运行状态
*/
public class C3_RunningState extends B1_LiftState {
/**
* 运行时不能开门
*/
@Override
public void open() {
//什么都不做
}
/**
* 运行时门肯定是关的
*/
@Override
public void close() {
//什么都不做
}
/**
* 执行运行方法
*/
@Override
public void run() {
System.out.println("电梯运行中");
}
/**
* 运行后可以停止
*/
@Override
public void stop() {
//环境设置为停止状态
super.context.setLiftState(A1_Context.STOPPING_STATE);
super.context.getLiftState().stop();
}
}
电梯停止状态
/**
* 电梯停止状态
*/
public class C4_StoppingState extends B1_LiftState {
/**
* 停下了要开门
*/
@Override
public void open() {
super.context.setLiftState(A1_Context.OPENNING_STATE);
super.context.getLiftState().open();
}
/**
* 门本来就是关着的
*/
@Override
public void close() {
//什么都不做
}
/**
* 停止后可以再运行
*/
@Override
public void run() {
super.context.setLiftState(A1_Context.RUNNING_STATE);
super.context.getLiftState().run();
}
/**
* 执行停止方法
*/
@Override
public void stop() {
System.out.println("电梯停止了");
}
}
客户端调用:
public class D1_Client {
public static void main(String[] args) {
A1_Context context = new A1_Context();
//定义初始状态为关门(共四种初始值)
context.setLiftState(new C4_StoppingState());
context.open();
context.close();
context.run();
context.stop();
}
}
电梯门开启
电梯门关闭
电梯运行中
电梯停止了
3.状态模式主要解决的问题
对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
4.状态模式的使用场景
- 行为随状态改变而改变的场景。
- 条件(if..else)、分支(switch)语句的代替者。
5.状态模式的优点
- 1:对状态转换规则进行了封装;
- 2:可以使用枚举类,枚举出所有可能的状态。但是需要在枚举状态之前确定状态的种类;
- 3:扩展性好。将所有与某个或者某些状态有关的行为放到了一个类对象中,这样方便管理,并且可以方便的新增状态,只需要改变对象状态就可以实现改变对象行为了;
- 4:代码简洁好维护。状态模式允许状态转换逻辑和状态对象合为一体,而不是一个巨大的条件语句块;
- 5:可以让多个不同的环境对象共享一个状态的对象,这样减少系统中对象的数量。
6.状态模式的缺点
- 1:增加对象和系统类的个数;
- 2:结构与实现比较复杂,如果使用不当,可能会造成程序结构和代码给人感觉很混乱的;
- 3:对开闭原则支持不好。
使用状态模式需要注意事项: 在行为受到状态约束的时候,使用状态模式,而且需要注意的是:状态最好不要超过5个; |