状态模式仅适用于状态数≥3、转移有明确约束、行为差异大的场景;少于3个状态用if-else或enum更轻量;状态转移须集中校验,避免逻辑混乱;同接口不同语义是其核心适用点。

状态模式只适合解决「状态数≥3、转移有明确约束、行为差异大」的切换问题。其他情况硬上反而更麻烦。
状态数量多且会增长
两个状态(比如on/off)用if-else或enum+switch足够清晰;一旦超过三个——比如订单的Pending、Paid、Shipped、Completed、Cancelled——每个操作都要检查所有分支,改一处容易漏别处。
- 新增状态时,
if-else要翻遍所有函数补条件;状态模式只需加一个类,不碰旧代码 - 状态数固定≤3、无扩展预期的场景(如嵌入式LED控制),用
std::variant或直接enum更轻量 - 状态名频繁变更或需运行时加载(如插件化协议解析器),继承方案比硬编码
switch更容易隔离变化
状态转移存在明确规则约束
如果「已发货」能退回「待支付」,或者「错误态」可以随意跳到任意状态,说明业务模型没理清,先画状态图再写代码——状态模式没法救逻辑混乱。
- 合法转移必须集中定义,例如在
Context::canTransitionTo()里用二维表或std::map<:pair stateid>, bool></:pair>校验 - 禁止把转移条件散落在各个
ConcreteState::handle()里,否则加新状态时极易漏边、埋幽灵bug - 调试时常见问题:状态指针没更新(
current_state = new_state忘了写)、旧状态析构时误触发资源释放
不同状态下同名操作行为差异显著
同样是调用click(),待支付订单跳收银台,已发货订单查物流,已取消订单直接报错——这种「接口相同、语义完全不同」的场景,正是状态模式最省力的地方。
立即学习“C++免费学习笔记(深入)”;
- 行为差异小的场景(比如只是改个日志前缀、开关某个标志位),上状态模式纯属杀鸡用牛刀
- 状态类必须是纯接口,不保存数据;所有上下文数据都从
Context*参数中读取,避免循环依赖 - 若多个状态需共享少量数据(如重试计数器),统一放在
Context里,别塞进各状态实例
真正难的不是写对虚函数和unique_ptr,而是定义清楚「什么算一个状态」——比如「网络连接中」和「正在重连」究竟该拆成两个状态,还是合并为一个带重试次数的复合状态。这个边界模糊点,往往比语法细节更决定项目成败。


















