Skip to main content

状态模式 (State)

场景问题​

问题案例​

考虑一个电梯系统,电梯有开门、关门、运行、停止等多种状态,不同状态下对外的操作行为不同。

不用模式的解决方案​

实现简化版本​

最直接的做法是用if-else语句判断当前状态:

public class Elevator {
private String state = "stopped";
public void open() {
if ("stopped".equals(state)) {
System.out.println("电梯门打开");
state = "opened";
}
}
public void close() {
if ("opened".equals(state)) {
System.out.println("电梯门关闭");
state = "closed";
}
}
public void run() {
if ("closed".equals(state)) {
System.out.println("电梯运行");
state = "running";
}
}
public void stop() {
if ("running".equals(state)) {
System.out.println("电梯停止");
state = "stopped";
}
}
}

使用示例​

Elevator elevator = new Elevator();
elevator.open();
elevator.close();
elevator.run();
elevator.stop();

有何问题​

  1. 状态判断分散在各方法中,难以维护。
  2. 新增状态或行为需修改大量代码。
  3. 违反开闭原则,扩展性差。

解决方案​

状态模式的定义​

允许对象在其内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

应用状态模式的思路​

  • 定义状态接口,每种状态实现具体行为。
  • 上下文持有当前状态对象,行为委托给状态对象。
  • 切换状态只需更换状态对象,无需修改上下文代码。

状态模式的结构​

  • State:抽象状态,定义所有行为接口。
  • OpenedState/ClosedState/RunningState/StoppedState:具体状态,实现具体行为。
  • ElevatorContext:上下文,持有当前状态,行为委托给状态对象。

状态模式的实现​

// 状态接口
public interface State {
void open(ElevatorContext ctx);
void close(ElevatorContext ctx);
void run(ElevatorContext ctx);
void stop(ElevatorContext ctx);
}

// 上下文
public class ElevatorContext {
private State state;
public void setState(State state) { this.state = state; }
public void open() { state.open(this); }
public void close() { state.close(this); }
public void run() { state.run(this); }
public void stop() { state.stop(this); }
}

// 具体状态
public class OpenedState implements State {
public void open(ElevatorContext ctx) { System.out.println("电梯门已打开"); }
public void close(ElevatorContext ctx) {
System.out.println("电梯门关闭");
ctx.setState(new ClosedState());
}
public void run(ElevatorContext ctx) { System.out.println("门开着不能运行"); }
public void stop(ElevatorContext ctx) { System.out.println("门开着已停止"); }
}
public class ClosedState implements State {
public void open(ElevatorContext ctx) {
System.out.println("电梯门打开");
ctx.setState(new OpenedState());
}
public void close(ElevatorContext ctx) { System.out.println("电梯门已关闭"); }
public void run(ElevatorContext ctx) {
System.out.println("电梯运行");
ctx.setState(new RunningState());
}
public void stop(ElevatorContext ctx) { System.out.println("电梯已停止"); }
}
public class RunningState implements State {
public void open(ElevatorContext ctx) { System.out.println("运行中不能开门"); }
public void close(ElevatorContext ctx) { System.out.println("运行中门已关闭"); }
public void run(ElevatorContext ctx) { System.out.println("电梯正在运行"); }
public void stop(ElevatorContext ctx) {
System.out.println("电梯停止");
ctx.setState(new StoppedState());
}
}
public class StoppedState implements State {
public void open(ElevatorContext ctx) {
System.out.println("电梯门打开");
ctx.setState(new OpenedState());
}
public void close(ElevatorContext ctx) { System.out.println("电梯门已关闭"); }
public void run(ElevatorContext ctx) {
System.out.println("电梯运行");
ctx.setState(new RunningState());
}
public void stop(ElevatorContext ctx) { System.out.println("电梯已停止"); }
}

使用示例​

public class Client {
public static void main(String[] args) {
ElevatorContext ctx = new ElevatorContext();
ctx.setState(new StoppedState());
ctx.open();
ctx.close();
ctx.run();
ctx.stop();
}
}

状态重写示例​

示例结构​


示例代码​

见上文"状态模式的实现"部分。


模式讲解​

状态模式的功能​

  • 封装状态切换逻辑,简化上下文代码。
  • 新增状态无需修改上下文,扩展性强。
  • 满足开闭原则。

实现成接口​

  • 状态通常定义为接口或抽象类。

使用工厂方法​

  • 可结合工厂方法模式,统一创建状态对象。

切换产品簇​

  • 可用于切换不同的状态实现,如不同设备、流程状态。

执行时序图​