当前位置: 首页 > news >正文

js设计模式-状态模式

一. 概念

状态模式是一种行为型设计模式,通过将对象在不同状态下的行为抽象为独立的对象,形成状态-行为映射。和策略模式有点像。
关键区别点如下:

  1. 状态对象可以自主控制状态转换,而策略对象不会自己更换策略
  2. 状态模式关注对象在不同状态下的行为差异,策略模式注重算法的封装与替换
  3. 状态模式的状态类通常需要引用当前对象(this.light),而策略类一般不需要
  4. 状态模式更强调生命周期内的状态变化,策略模式更强调运行时的算法选择

二. 应用场景举例

1. 举一个打开/关闭开关的案例

1. 常规方案

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><button>按下开关</button><script>class Light {constructor() {this.state = 'off'; // 给电灯设置初始状态 off this.button = null; // 电灯开关按钮}init () {this.button = document.querySelector('button'),self = this;this.button.onclick = function () {self.buttonWasPressed();}}buttonWasPressed () {if (this.state === 'off') {console.log('开灯');this.state = 'on';} else if (this.state === 'on') {console.log('关灯');this.state = 'off';}}}const light = new Light();light.init();</script>
</body></html>

2. 利用状态模式

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><script>const FSM = {off: {buttonWasPressed: function () {console.log('关灯');this.button.innerHTML = '下一次按我是开灯';this.currState = FSM.on;}},on: {buttonWasPressed: function () {console.log('开灯');this.button.innerHTML = '下一次按我是关灯';this.currState = FSM.off;}}};class Light {constructor() {this.currState = FSM.off; // 设置当前状态this.button = null;}init () {var button = document.createElement('button'),self = this;button.innerHTML = '已关灯';this.button = document.body.appendChild(button);this.button.onclick = function () {self.currState.buttonWasPressed.call(self); // 把请求委托给 FSM 状态机}}}const light = new Light();light.init(); </script>
</body></html>

两种方式对比:
方案1:
适合场景: 状态简单、需求固定,且无扩展需求的系统。
优点: 代码简洁,易于快速实现。
缺点: 状态或行为增加时代码膨胀(如需添加 dim 状态需添加 else if)。
方案2:
适合场景: 需要频繁修改或扩展的状态系统(如游戏、设备控制等)。
优点: 扩展性强,维护成本低,逻辑清晰。
缺点: 初期代码量略多,需理解状态机设计模式。

总结:
状态机(方案二) 是模式化、解耦的优雅实现,适合复杂场景。
条件判断(方案一) 是快速实现的简易方案,适合简单需求。

2. 当开关的状态有多种时举例

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><button>按下开关</button><script>class OffLightState {constructor(light) {this.light = light;}buttonWasPressed () {alert('弱光');this.light.setState(this.light.weakLightState);}}class WeakLightState {constructor(light) {this.light = light;}buttonWasPressed () {alert('强光');this.light.setState(this.light.strongLightState);}}class StrongLightState {constructor(light) {this.light = light;}buttonWasPressed () {alert('关灯');this.light.setState(this.light.offLightState);}}class Light {constructor() {this.offLightState = new OffLightState(this);this.weakLightState = new WeakLightState(this);this.strongLightState = new StrongLightState(this);this.currState = this.offLightState;this.button = null;}init () {this.button = document.querySelector('button');this.button.onclick = () => this.currState.buttonWasPressed();}setState (newState) {this.currState = newState;}}const light = new Light();light.init();</script>
</body></html>

构造Light实例时

Light()→ 初始化3个状态实例并传入自身(this)→ 设置初始状态为关灯状态→ 预留按钮变量

设计优势

  1. 可扩展性:增加新状态仅需添加新状态类,不修改已有代码
  2. 维护简单:状态逻辑与主类解耦,修改某个状态不会影响其他部分
  3. 清晰的状态转移:每个状态明确定义迁移目标,避免条件嵌套

文章转载自:

http://SnrS5yIk.fmznd.cn
http://PXZV92uE.fmznd.cn
http://xQTxbcF4.fmznd.cn
http://2BE1moAC.fmznd.cn
http://LabC7XdK.fmznd.cn
http://pG5HRdNd.fmznd.cn
http://TTCbpBKo.fmznd.cn
http://qmscCelR.fmznd.cn
http://61KkxwYo.fmznd.cn
http://9sYA89sz.fmznd.cn
http://HZm3xoX3.fmznd.cn
http://9rt4PVe6.fmznd.cn
http://OYqMByPU.fmznd.cn
http://FK9isGwv.fmznd.cn
http://qBhoGdSK.fmznd.cn
http://i77HbzvI.fmznd.cn
http://38ObYHzl.fmznd.cn
http://Nh3zWdW1.fmznd.cn
http://1k0kWByb.fmznd.cn
http://s6Hh3sma.fmznd.cn
http://sbc6Kl8M.fmznd.cn
http://ybcPziuI.fmznd.cn
http://7T4R9paH.fmznd.cn
http://OYKnLIFJ.fmznd.cn
http://GNC5y1yJ.fmznd.cn
http://OEubosSy.fmznd.cn
http://i5VyjPFX.fmznd.cn
http://LofiO6OX.fmznd.cn
http://1SWy8Tu9.fmznd.cn
http://VMeBK5ul.fmznd.cn
http://www.dtcms.com/a/368119.html

相关文章:

  • 一文从零部署vLLM+qwen0.5b(mac本地版,不可以实操GPU单元)
  • Python核心基础:运算符、流程控制与字符串操作详解
  • Follow 幂如何刷屏?拆解淘宝闪购×杨幂的情绪共振品牌营销
  • 嵌入式学习4——硬件
  • 数据标注:人工智能视觉感知的基石
  • 【Linux系统】POSIX信号量
  • 【Python - 类库 - requests】(02)使用“requests“发起GET请求的详细教程
  • XSCT/Vitis 裸机 JTAG 调试与常用命令
  • 【GitHub每日速递】不止 TeamViewer 替代!RustDesk 与 PowerToys,Windows 效率神器
  • 使用海康机器人相机SDK实现基本参数配置(C语言示例)
  • Go 服务注册 Nacos 的坑与解决方案——从 404 到连接成功的排查之路
  • 智能相机还是视觉系统?一文讲透工业视觉两大选择的取舍之道
  • Go语言中atomic.Value结构体嵌套指针的直接修改带来的困惑
  • react+umi项目如何添加electron的功能
  • 告别 OpenAI SDK:如何使用 Python requests 库调用大模型 API(例如百度的ernie-4.5-turbo)
  • 《sklearn机器学习——聚类性能指数》同质性,完整性和 V-measure
  • C#海康车牌识别实战指南带源码
  • 五、Docker 核心技术:容器数据持久化之数据卷
  • (计算机网络)DNS解析流程及两种途径
  • 3-8〔OSCP ◈ 研记〕❘ WEB应用攻击▸REST API枚举
  • Tabby使用sftp上传文件服务器ssh一直断开
  • 解密大语言模型推理:输入处理背后的数学与工程实践
  • python 自动化在web领域应用
  • FDTD_3 d mie_仿真
  • Electron 安全性最佳实践:防范常见漏洞
  • SAP ERP公有云详解:各版本功能对比与选型
  • Linux:进程信号理解
  • 深度学习:Dropout 技术
  • Linux 磁盘扩容及分区相关操作实践
  • 【前端】使用Vercel部署前端项目,api转发到后端服务器