一、引言
在电梯运行的模型中,你是否考虑过这样写
java
if (state.equals("运行")) {
// 忽略开门请求
} else if (state.equals("停止")) {
// 执行开门
} else if (state.equals("开门")) {
// 等待用户进入
}
你可能只是在控制一个简单的"电梯",但这段代码告诉你:
-
一堆
if-else
把状态和行为耦合死了; -
状态变多,逻辑混乱,难以维护;
-
改功能=地狱级维护
那该怎么解决这个问题呢?就用今天我们要讨论的状态模式最恰当不过了。
二、状态模式(State Pattern)
定义:将对象的状态封装成独立类,状态之间可以互相切换,对象在不同状态下表现出不同行为。
通俗讲:让对象的行为"随着状态而改变",不再由 if-else 控制,而由"状态类"自己说了算!
举一个生活中的例子:电梯的行为受"状态"决定
电梯状态 = 它现在在哪一层 + 开没开门 + 是否在运行
状态 vs 行为对照表:
当前状态 | 用户按"开门" |
---|---|
开门状态 | ❗门已打开 |
关门+停止状态 | ✅ 打开门 |
运行状态 | 🚫 无法开门 |
四、为什么状态模式更适合
假设我们用状态模式重写电梯逻辑,代码看起来像这样:
java
elevator.open(); // 当前状态是"停止",所以可以打开门
elevator.run(); // 当前是"关门",可以运行
elevator.open(); // 当前是"运行中",无法开门
每个状态都封装在独立类中,电梯对象只管当前处于什么状态,行为交由状态类处理。代码简介,逻辑清晰。
五、状态模式类图

plantuml
@startuml
interface LiftState {
+open(): void
+close(): void
+run(): void
+stop(): void
}
class OpenState implements LiftState
class RunningState implements LiftState
class StoppedState implements LiftState
class Elevator {
-state: LiftState
+setState(s: LiftState)
+open()
+close()
+run()
+stop()
}
Elevator --> LiftState
LiftState <|.. OpenState
LiftState <|.. RunningState
LiftState <|.. StoppedState
@enduml
六、完整 Java 实战代码
1. 状态接口
java
public interface LiftState {
void open(Elevator context);
void close(Elevator context);
void run(Elevator context);
void stop(Elevator context);
}
2. 三种具体状态类(开门、运行、停止)
开门状态
java
public class OpenState implements LiftState {
public void open(Elevator context) {
System.out.println("门已经开着");
}
public void close(Elevator context) {
System.out.println("门关闭了");
context.setState(new StoppedState());
}
public void run(Elevator context) {
System.out.println("🚫 开着门不能运行");
}
public void stop(Elevator context) {
System.out.println("电梯停止中");
}
}
运行状态
java
public class RunningState implements LiftState {
public void open(Elevator context) {
System.out.println("🚫 运行中不能开门");
}
public void close(Elevator context) {
System.out.println("门已经关着");
}
public void run(Elevator context) {
System.out.println("电梯正在运行中...");
}
public void stop(Elevator context) {
System.out.println("运行结束,电梯停止");
context.setState(new StoppedState());
}
}
停止状态
java
public class StoppedState implements LiftState {
public void open(Elevator context) {
System.out.println("打开门");
context.setState(new OpenState());
}
public void close(Elevator context) {
System.out.println("门已经关闭");
}
public void run(Elevator context) {
System.out.println("开始运行");
context.setState(new RunningState());
}
public void stop(Elevator context) {
System.out.println("已经停止");
}
}
3. 电梯本体类
java
public class Elevator {
private LiftState state;
public Elevator() {
this.state = new StoppedState(); // 默认初始状态
}
public void setState(LiftState 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);
}
}
4. 测试代码
java
public class Client {
public static void main(String[] args) {
Elevator lift = new Elevator();
lift.open(); // 打开门(从停止)
lift.close(); // 关门(切回停止)
lift.run(); // 开始运行
lift.open(); // 运行中不能开门
lift.stop(); // 停止
lift.open(); // 打开门
}
}
5. 代码输出
打开门
门关闭了
开始运行
🚫 运行中不能开门
运行结束,电梯停止
打开门
是不是比 if-else
的实现清晰太多?
七、总结
同一个对象,不同状态下表现出不同行为,行为被"状态对象"接管,不靠或减少if else判断语句。
优势 | 描述 |
---|---|
✅ 可扩展 | 新增状态只需加类,不动旧代码 |
✅ 可读性强 | 不再靠状态变量判断,行为清晰 |
✅ 分工明确 | 每个状态类只负责自己状态下该干嘛 |
🚫 类增多 | 状态太多时类数量多,但逻辑不乱 |
适用场景举例
- 电梯状态管理(运行/停止/开门)
- 游戏角色行为(攻击/防御/死亡)
- 表单状态(草稿/审核/发布)
- 网络连接状态(连接中/已连接/断开)
- 审批流程节点状态(待审/驳回/通过)
八、参考
