状态模式
定义
当一个对象内在的状态改变时,允许其改变行为,这个对象看似改变了其类
状态模式的核心是封装,状态的变更引起行为的变更,从外部看来就好像这个对象对应的类发生了变化一样。
优缺点、应用场景
优点
- 结构清晰。避免使用switch和if-else来处理每个状态转变到另一个状态的细节
- 遵循设计原则。很好地体现了开闭原则和单一职责原则,每个状态作为一个独立类,专注自己的责任。
- 封装性好。高层模型不需要了解子类的具体实现,只需要按照暴露出的流程使用即可。
缺点
- 子类会太多。对于一个事物来说,状态多就会导致类膨胀,并且不同状态对于事件都有不同的处理方法
应用场景
- 行为随状态的改变而改变
- 条件、分支判断语句的替代
代码模拟场景
使用电梯时的状态,包括:开门、关门、运行、停止。每种状态向其他状态转变的逻辑都不同。
开门(Open) | 关门(Close) | 运行(Run) | 停止(Stop) | |
---|---|---|---|---|
开门状态 | √ | × | × | |
关门状态 | √ | √ | √ | |
运行状态 | × | × | √ | |
停止状态 | √ | √ | √ |
状态模式
UML图
状态的抽象和实现
/**
* 抽象电梯状态
*/
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();
}
/**
* 电梯开门状态
*/
public class OpenState extends LiftState {
@Override
public void open() {
System.out.println("电梯开门...");
}
/**
* 开门的状态下可以关门
*/
@Override
public void close() {
// 状态修改
super.context.setLiftState(Context.CLOSE_STATE);
// 动作委托CloseState来执行
super.context.getLiftState().close();
}
/**
* 不能运行
*/
@Override
public void run() {
}
/**
* 不能停止
*/
@Override
public void stop() {
}
}
/**
* 电梯关门状态
*/
public class CloseState extends LiftState {
/**
* 关门的状态下可以开门
*/
@Override
public void open() {
super.context.setLiftState(Context.OPEN_STATE);
super.context.getLiftState().open();
}
@Override
public void close() {
System.out.println("电梯关门...");
}
/**
* 门关闭了就可以运行
*/
@Override
public void run() {
super.context.setLiftState(Context.RUN_STATE);
super.context.getLiftState().run();
}
/**
* 关着门不按楼层也可以,就停那了
*/
@Override
public void stop() {
super.context.setLiftState(Context.STOP_STATE);
super.context.getLiftState().stop();
}
}
/**
* 电梯运行状态
*/
public class RunState 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.CLOSE_STATE);
super.context.getLiftState().stop();
}
}
/**
* 电梯关闭状态
*/
public class StopState extends LiftState {
/**
* 停下可以开门
*/
@Override
public void open() {
super.context.setLiftState(Context.OPEN_STATE);
super.context.getLiftState().open();
}
/**
* 停止可以关门
*/
@Override
public void close() {
super.context.setLiftState(Context.CLOSE_STATE);
super.context.getLiftState().close();
}
/**
* 可以再运行起来
*/
@Override
public void run() {
super.context.setLiftState(Context.RUN_STATE);
super.context.getLiftState().run();
}
@Override
public void stop() {
System.out.println("电梯停下了...");
}
}
上下文对象
/**
* 上下文对象
*/
public class Context {
/**
* 定义当前电梯的状态
*/
private LiftState liftState;
public static final LiftState OPEN_STATE = new OpenState();
public static final LiftState CLOSE_STATE = new CloseState();
public static final LiftState RUN_STATE = new RunState();
public static final LiftState STOP_STATE = new StopState();
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 LiftState getLiftState() {
return liftState;
}
public void setLiftState(LiftState liftState) {
this.liftState = liftState;
this.liftState.setContext(this);
}
}
入口类
private static void statePattern() {
Context context = new Context();
// 定义电梯初始状态为关闭
context.setLiftState(Context.CLOSE_STATE);
context.open();
context.close();
context.run();
context.stop();
}
结果
参考书籍
秦小波《设计模式之禅》