定义:状态模式也称为状态机模式,是允许对象在内部状态发生改变时改变它的行为,对象看起来好像是修改了它的类。
应用场景:
1. 行为随状态改变而改变的场景
2. 一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态在实际开发中如电商类项目的订单,审核流程等可以使用状态模式,下面使用电梯来举例状态模式的应用:
/**
* create by Alan at 2020/3/26 9:35
* description:抽象电梯状态类
*/
public abstract class LiftState {
//环境上下文
protected Context 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();
}
/**
* create by Alan at 2020/3/26 9:38
* description:开门状态
*/
public class OpenningState extends LiftState{
@Override
public void open() {
System.out.println("电梯门开启..");
}
@Override
public void close() {
//状态修改
super.context.setLiftState(Context.closingState);
//动作委托给CloseState来执行
super.context.getLiftState().close();
}
@Override
public void run() {
}
@Override
public void stop() {
}
}
/**
* create by Alan at 2020/3/26 9:38
* description:关门状态
*/
public class ClosingState extends LiftState{
@Override
public void open() {
//设置为开门状态
super.context.setLiftState(Context.openningState);
super.context.getLiftState().open();
}
@Override
public void close() {
System.out.println("电梯门关闭...");
}
@Override
public void run() {
super.context.setLiftState(Context.runningState);
super.context.getLiftState().run();
}
@Override
public void stop() {
super.context.setLiftState(Context.stopingState);
super.context.getLiftState().stop();
}
}
/**
* create by Alan at 2020/3/26 9:38
* description:运行状态
*/
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.stopingState);
super.context.getLiftState().stop();
}
}
/**
* create by Alan at 2020/3/26 9:38
* description:停止状态
*/
public class StopingState 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("电梯停止了...");
}
}
/**
* create by Alan at 2020/3/26 9:37
* description:上下文类
*/
public class Context {
//定义出所有状态
public final static OpenningState openningState = new OpenningState();
public final static ClosingState closingState = new ClosingState();
public final static RunningState runningState = new RunningState();
public final static StopingState stopingState = new StopingState();
//当前电梯状态
public 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();
}
}
/**
* create by Alan at 2020/3/26 9:55
* description:
*/
public class Client {
public static void main(String[] args) {
Context context = new Context();
//设置不同的状态会执行不同操作
context.setLiftState(new RunningState());
context.run();
context.open();
context.close();
context.stop();
}
}
结果:
电梯在运行中...
电梯停止了...
上述代码根据当前所处的状态,执行可以运行的事件来扭转状态。
优点:
1. 结构清晰:将状态独立为类,消除了冗余的if...else或switch...case语句,使代码更加简洁,提高系统可维护性
2. 将状态转换显示化:通常的对象内部都是使用数值类型来定义状态,状态的切换是通过赋值今进行表现,不够直观;而使用状态类,在切换状态时,是以不同的类进行表示,转换目的更加明确
3. 状态类职责明确且具备扩展性
缺点:
1. 类膨胀:如果一个事务具备的状态很多,则需要简历很多状态类
2. 状态模式的结构与实现都较为复杂,使用不当会导致程序结构和代码混乱
3. 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新贼的状态,而且修改某个状态类的行为也需要修改对应类的源代码
Spring中有一个状态机,可以直接使用,目前还没有研究,等研究了在讨论状态机是怎么玩的。