什么是状态模式
状态模式是针对状态机模型的编程套路,首先要知道状态机是什么。
状态机是一种数学模型,用于对事物状态的变化进行描述。不说那么学术的概念了,用具体的例子来解释会更容易理解。
电梯应该都知道吧,电梯工作过程可以简化为几种状态:开门状态、关门状态、运行状态、停止状态。
- 开门状态下可以关门
- 关门状态下可以运行或者再次开门
- 运行状态下可以停止
- 停止状态下可以开门或者再次运行
用状态图表示就是:
在现实中,电梯停止后会自动开门,我这里的状态模型把“自动化”因素给剔除了,所以停止后的电梯还有可能进入运行状态。
编程时如果遇到这样的状态机模型,就可以考虑使用状态模式对其进行编码。
设计与实现
初级方案
这里先给出一个初级方案,也是通常情况下,大多数人最容易想到的方案。如果不感兴趣,请直接去下一节看状态模式的实现。
初级方案实现思路很简单,就是熟练使用各种条件判断。
代码大概就像下面的样子:
// 四种状态枚举
public enum StateEnum {
OPENING, CLOSING, RUNNING, STOPPING
}
// 电梯接口定义
public interface Elevator {
void setState(StateEnum state); // 设置当前状态
void open(); // 开门指令
void close(); // 关门指令
void run(); // 运行指令
void stop(); // 停止指令
}
// 电梯接口实现
public class ElevatorImpl implements Elevator {
private StateEnum state;
@Override
public void setState(StateEnum state) {
this.state = state;
}
@Override
public void open() {
if (this.state == StateEnum.CLOSING || this.state == StateEnum.STOPPING) {
System.out.println("电梯开门");
this.setState(StateEnum.OPENING);
}
}
@Override
public void close() {
if (this.state == StateEnum.OPENING) {
System.out.println("电梯关门");
this.setState(StateEnum.CLOSING);
}
}
@Override
public void run() {
if (this.state == StateEnum.CLOSING || this.state == StateEnum.STOPPING) {
System.out.println("电梯运行");
this.setState(StateEnum.RUNNING);
}
}
@Override
public void stop() {
if (this.state == StateEnum.RUNNING) {
System.out.println("电梯停止");
this.setState(StateEnum.STOPPING);
}
}
}
// 测试方法
public static void main(String[] args) {
Elevator elevator = new ElevatorImpl();
elevator.setState(StateEnum.STOPPING);
elevator.open();
elevator.close();
elevator.run();
elevator.stop();
}
这样的代码容易想到,实现起来也很容易,但是有两个明显的缺点:
- 判断条件太多,令人眼花缭乱,写的时候容易出错
- 如果有新增状态,每个指令方法都得修改,违反开闭原则
状态模式
初级方案是将电梯作为一个主体,状态为其属性,这样封装代码符合人类的自然思维,必然也会导致内部属性状态判断较为繁杂。
状态模式则是在初级方案的基础上,将状态从电梯属性中拆分出来,作为独立的主体。电梯只提供工作指令的接口,指令实际执行过程则是委托给各个状态主体。
来体会一下具体的代码设计方案:
// 电梯状态定义
public abstract class ElevatorState {
protected Elevator elevator;
public void setElevator(Elevator elevator) {
this.elevator = elevator;
}
public abstract void open();
public abstract void close();
public abstract void run();
public abstract void stop();
}
// 电梯接口
public interface Elevator {
ElevatorState getState(); // 获取电梯状态
void setState(ElevatorState state); // 设置电梯状态
void open(); // 开门指令
void close(); // 关门指令
void run(); // 运行指令
void stop(); // 停止指令
}
// 开门状态
public class OpeningState extends ElevatorState {
@Override
public void open() {
System.out.println("电梯开门");
}
@Override
public void close() {
super.elevator.setState(ElevatorImpl.CLOSING_STATE);
super.elevator.getState().close();
}
@Override
public void run() {}
@Override
public void stop() {}
}
// 关门状态
public class ClosingState extends ElevatorState {
@Override
public void open() {
super.elevator.setState(ElevatorImpl.OPENING_STATE);
super.elevator.getState().open();
}
@Override
public void close() {
System.out.println("电梯关门");
}
@Override
public void run() {
super.elevator.setState(ElevatorImpl.RUNNING_STATE);
super.elevator.getState().run();
}
@Override
public void stop() {}
}
// 运行状态
public class RunningState extends ElevatorState {
@Override
public void open() {}
@Override
public void close() {}
@Override
public void run() {
System.out.println("电梯运行");
}
@Override
public void stop() {
super.elevator.setState(ElevatorImpl.STOPPING_STATE);
super.elevator.getState().stop();
}
}
// 停止状态
public class StoppingState extends ElevatorState {
@Override
public void open() {
super.elevator.setState(ElevatorImpl.OPENING_STATE);
super.elevator.getState().open();
}
@Override
public void close() {}
@Override
public void run() {
super.elevator.setState(ElevatorImpl.RUNNING_STATE);
super.elevator.getState().run();
}
@Override
public void stop() {
System.out.println("电梯停止");
}
}
// 电梯实现类
public class ElevatorImpl implements Elevator {
public final static OpeningState OPENING_STATE = new OpeningState();
public final static ClosingState CLOSING_STATE = new ClosingState();
public final static RunningState RUNNING_STATE = new RunningState();
public final static StoppingState STOPPING_STATE = new StoppingState();
private ElevatorState state;
@Override
public ElevatorState getState() {
return state;
}
@Override
public void setState(ElevatorState state) {
this.state = state;
this.state.setElevator(this);
}
@Override
public void open() {
this.state.open();
}
@Override
public void close() {
this.state.close();
}
@Override
public void run() {
this.state.run();
}
@Override
public void stop() {
this.state.stop();
}
}
// 测试方法
public static void main(String[] args) {
Elevator elevator = new ElevatorImpl();
elevator.setState(new ClosingState());
elevator.open();
elevator.close();
elevator.run();
elevator.stop();
}
看,类里面的条件判断语句都没有了,新增状态也很方便。
这就是状态模式的作用,实现状态机的运行过程,但是却消除了各种条件判断,很好的解耦了状态之间的联系。