专栏名称: 前端大全
分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯
目录
相关文章推荐
51好读  ›  专栏  ›  前端大全

别再写一堆 if-else 了:用状态模式优雅管理状态行为

前端大全  · 公众号  · 前端  · 2025-05-28 10:06

正文

请到「今天看啥」查看全文


这就是多态在起作用:一个方法调用,根据具体的状态 对象 不同,表现出不同的行为。

避免条件语句过于复杂

使用状态模式的主要动机之一,就是为了消除代码中重复且分散的条件逻辑。如果一个对象的行为会根据状态变化而改变,你可能会倾向于用枚举或布尔标志来跟踪状态,然后在每个需要根据状态处理的地方写 switch if 语句。这种做法会让代码变得臃肿、难以维护。

状态模式的做法是把每种状态下的逻辑封装在独立的类中:

  • 每种状态的逻辑都放在自己专属的类中(比如 “静音模式” 的所有逻辑都放在 SilentState 里)。
  • 上下文(Context)对象的代码会变得更简单,不再需要处理大段的条件判断逻辑。
  • 增加新的状态或修改已有状态,不需要在多个地方修改庞大的 switch 语句 —— 只需新增或修改一个状态类。

经典定义中提到:“当某些操作包含大量依赖于对象状态的条件语句时,状态模式会将每个条件分支封装在独立的类中,把状态当作一个独立的对象来看待。”

这种封装方式符合开闭原则(Open/Closed Principle):我们可以在不修改原有上下文或其他状态类的情况下引入新的状态。同时也符合单一职责原则(Single Responsibility Principle),因为每个状态类只负责处理一种状态下的行为。

什么时候该使用(或不使用)状态模式

适合使用状态模式的场景:
  • 当一个对象的行为依赖其当前状态,并且它在运行时需要根据状态改变行为时。如果你发现自己在多个地方都写着 “如果状态是 X 做这个,状态是 Y 做那个”,那可能就适合用状态模式。
  • 当一个对象有多个行为逻辑,并且这些逻辑可以明确地按状态划分。例如,手机的响铃、震动、静音记录等行为都可以独立处理。
  • 想要避免状态判断逻辑重复出现在多个方法中。使用状态模式后,这些行为被集中封装在状态类中,不再重复。
  • 预计未来可能会增加新的状态,或每个状态下的逻辑会变得更复杂。状态模式的结构更容易扩展(新增一个状态类)或修改(只需改动一个类的代码)。
不适合使用状态模式的情况或需谨慎使用:
  • 如果对象只有一两个状态,而且每种状态下的行为差异非常简单,那么使用状态模式可能就有点小题大做了。用普通的条件判断反而更清晰。
  • 如果状态切换很少发生,或者每种状态的逻辑基本不会变,那用状态模式引入的一堆类可能并不值得。
  • 如果状态数量固定且逻辑简单明确,使用枚举加 switch 语句可能就足够了。状态模式适用于那些状态复杂且易变的场景。

可以这样想:一个只有两个状态的小状态机,用 if 来管理也没问题。但如果是一个有十种状态、状态之间还有复杂切换逻辑的状态机,那用状态模式结构化处理会更好维护。

为什么状态模式比枚举和标志变量更好?

一开始,很多人会选择用枚举或布尔标志来表示状态,比如:

enum Mode { normal, vibrate, silent }

然后用类似这样的逻辑处理行为:

if(mode == Mode.normal){
// 响铃
}else if(mode == Mode.vibrate){
// 震动
}else if(mode == Mode.silent){
// 保持静音
}

这种方式起初是可行的,但随着程序变复杂,会出现以下问题:

  • 逻辑分散 - 如果多个行为都依赖状态判断,你就会在很多方法里看到类似的 if/else switch ,例如 handleCall() notifyMessage() alarmRing() 等等。状态行为稍有改动,就得到处找这些条件语句并改动。
  • 违反开闭原则 - 比如你想新增一个 “请勿打扰” 模式(Do Not Disturb),就得修改所有相关的 switch 语句。每次修改都有可能引入 bug,影响原有功能。
  • 维护困难 - 状态和条件越来越多,代码就越难阅读和维护,容易变成一个嵌在业务逻辑中的 “巨型状态机”。

状态模式通过封装各个状态的行为,解决了这些问题。你不再需要一个大函数来处理各种分支,而是有多个小类,各自处理自己的状态行为。这样结构更清晰:

  • Phone






请到「今天看啥」查看全文


推荐文章
248游戏  ·  【测试】你的恋爱智商有多少?
8 年前
柳林大小事  ·  老公工地一幕,媳妇看哭了...
7 年前
声乐助手  ·  7月30日|每天一道乐理习题
7 年前