Java 编程之状态模式

一、引言

在电梯运行的模型中,你是否考虑过这样写

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判断语句。

优势 描述
✅ 可扩展 新增状态只需加类,不动旧代码
✅ 可读性强 不再靠状态变量判断,行为清晰
✅ 分工明确 每个状态类只负责自己状态下该干嘛
🚫 类增多 状态太多时类数量多,但逻辑不乱

适用场景举例

  • 电梯状态管理(运行/停止/开门)
  • 游戏角色行为(攻击/防御/死亡)
  • 表单状态(草稿/审核/发布)
  • 网络连接状态(连接中/已连接/断开)
  • 审批流程节点状态(待审/驳回/通过)

八、参考

《23种设计模式概览》

相关推荐
章豪Mrrey nical4 小时前
前后端分离工作详解Detailed Explanation of Frontend-Backend Separation Work
后端·前端框架·状态模式
超级大只老咪5 小时前
数组相邻元素比较的循环条件(Java竞赛考点)
java
小浣熊熊熊熊熊熊熊丶5 小时前
《Effective Java》第25条:限制源文件为单个顶级类
java·开发语言·effective java
毕设源码-钟学长5 小时前
【开题答辩全过程】以 公交管理系统为例,包含答辩的问题和答案
java·eclipse
啃火龙果的兔子5 小时前
JDK 安装配置
java·开发语言
星哥说事5 小时前
应用程序监控:Java 与 Web 应用的实践
java·开发语言
派大鑫wink6 小时前
【JAVA学习日志】SpringBoot 参数配置:从基础到实战,解锁灵活配置新姿势
java·spring boot·后端
xUxIAOrUIII6 小时前
【Spring Boot】控制器Controller方法
java·spring boot·后端
Dolphin_Home6 小时前
从理论到实战:图结构在仓库关联业务中的落地(小白→中级,附完整代码)
java·spring boot·后端·spring cloud·database·广度优先·图搜索算法
等....6 小时前
Miniconda使用
开发语言·python