← 返回题目列表

策略模式和状态模式有什么区别?

高频 中等 第 6 / 26 题 更新于 2026/07/28
策略模式状态模式设计模式对比行为型模式

简化版

策略模式关注“同一个行为有多种算法可替换”,策略通常由外部选择;状态模式关注“对象状态变化导致行为变化”,状态通常由对象内部流转。简单记:策略是可选方案,状态是生命周期阶段。

详细版

策略模式和状态模式结构很像,都是定义接口,再用多个实现类封装不同的行为。但它们的意图不同。

策略模式:

  • 目的是替换算法或业务规则;
  • 调用方通常知道或决定使用哪种策略;
  • 各个策略之间通常相互独立;
  • 重点是减少分支、支持扩展。

状态模式:

  • 目的是让对象在不同状态下表现出不同行为;
  • 状态切换通常由对象内部规则驱动;
  • 状态之间存在流转关系;
  • 重点是管理状态机和状态相关行为。

比如优惠计算用策略模式更合适,因为用户可以选择或系统可以配置不同优惠算法;订单从待支付、已支付、已发货、已完成之间流转,更像状态模式。

完整版教学

一、为什么两者容易混淆

策略模式和状态模式的代码结构非常相似:

接口
  -> 实现 A
  -> 实现 B
  -> 实现 C

调用方也都是面向接口调用方法。正因为结构像,面试官经常问它们区别,考察的是你能不能从“设计意图”判断模式,而不是只看类图。

设计模式不是背类图,核心要看它解决的变化点是什么。

二、策略模式解决算法选择

策略模式面对的是“同一个问题有多种解法”。

例如:

  • 支付方式:余额、银行卡、第三方支付;
  • 排序算法:快速排序、归并排序、堆排序;
  • 优惠规则:满减、折扣、会员价;
  • 导出格式:Excel、CSV、PDF。

这些策略之间通常没有生命周期关系。选择哪一个,取决于外部参数、配置或用户操作。

比如支付时,用户选了余额支付,就执行余额支付策略;用户选了银行卡,就执行银行卡策略。

三、状态模式解决状态流转

状态模式面对的是“同一个对象处于不同状态时行为不同”。

例如订单状态:

  • 待支付;
  • 已支付;
  • 已发货;
  • 已完成;
  • 已取消。

这些状态之间通常有合法流转关系。比如待支付可以取消,也可以支付;已完成通常不能再取消。

状态对象不仅封装行为,还可能负责推动状态迁移:

待支付 --支付--> 已支付 --发货--> 已发货 --确认收货--> 已完成

这和策略模式的独立算法选择很不一样。

四、判断方法:看变化来自哪里

可以用三个问题快速区分:

  1. 行为变化是由外部选择驱动,还是由对象内部状态驱动?
  2. 多个实现之间是否有流转关系?
  3. 当前实现是否代表对象生命周期的一部分?

如果是“外部选择不同算法”,倾向策略模式。

如果是“对象状态变化导致行为变化”,倾向状态模式。

五、面试中可以这样举例

优惠计算:

订单金额 + 优惠类型 -> 选择满减/折扣/会员策略

这是策略模式。因为优惠规则是可替换算法。

订单操作:

待支付订单允许支付,已取消订单不允许支付

这是状态模式。因为行为取决于订单当前状态。

两者可以组合使用。例如订单在“待支付”状态下,支付动作内部还可以使用不同支付策略。

六、外部选择与内部迁移的差异

同一笔 200 元订单可任选两种优惠算法,这是 2 个策略;订单从待支付到已支付再到已发货,则是 3 个有方向的状态节点。

strategy: selector -> algorithm; state: current state --event--> next state

这个推演把模式带来的收益和成本放在同一条调用链上。设计评审时既要确认结果正确,也要确认额外层次没有改变原有契约。

七、边界、代价与验证

检查维度应确认的内容
正确性看类图很难区分,必须追问谁触发变化、实现之间是否存在生命周期迁移。
适用边界策略通常彼此独立,状态必须定义合法迁移;两者可组合,例如待支付状态内部选择支付策略。
测试证据覆盖正常路径、异常路径、空值或未知类型,并断言调用次数与顺序
运行成本记录额外对象、调用层数、延迟、线程或内存开销,不用模式名称代替测量

模式落地后要用单元测试验证独立职责,用集成测试验证对象装配和真实调用入口。涉及并发、远程或异步时,还要补充竞态、超时、重复执行与资源释放测试。

易错点:看类图很难区分,必须追问谁触发变化、实现之间是否存在生命周期迁移。

八、常见误区与追问

  • 误区:状态模式只是由系统自动选择的策略模式。 状态对象代表生命周期节点且存在迁移约束,语义不只是选择来源不同。
  • 误区:用了策略模式,系统里就不该再出现任何条件判断。 策略消除的是反复扩张的业务算法分支;选择策略、校验输入和兜底仍可能需要有限判断。
  • 误区:示例代码能运行,就代表模式边界设计正确。 能运行只证明一条路径,仍要检查异常、并发、顺序、生命周期以及新增实现时是否修改稳定代码。
  • 追问:状态对象能否由外部直接替换? 应通过受控事件和迁移规则改变,否则会绕过状态机不变量。
  • 追问:策略对象可以保存本次请求的可变状态吗? 容器单例策略通常不应保存请求状态,应把订单、用户等数据作为参数传入,否则并发调用会相互污染。
  • 追问:怎样验证这套设计没有改变原有语义? 先做基线行为测试,再对新增层验证返回值、异常类型、调用次数和顺序;性能敏感处还要比较改造前后的量化指标。

九、加强记忆

策略模式和状态模式长得像,但一个是“方案选择”,一个是“状态流转”。策略通常由外部决定,策略之间相互独立;状态通常由对象生命周期驱动,状态之间存在迁移规则。