关于状态模式我所知道的

简介: 关于状态模式我所知道的

image.png


关键词:行为型 状态模式 StatePattern


解决什么问题?


状态机 State Machine:

一种数学模型,用于描述状态转换的逻辑。常用实现的方法:分支逻辑法、查表法、状态模式。

有三部分组成:状态(State)、事件(Event)、动作(Action)。

事件(转移条件)触发状态的转移及动作的执行。其中,动作不是必须的。


image.png

状态模式是状态机的一种实现方式。

实例对象内部状态发生改变,方法也发生改变。看上去就像换了个所属类一样。


应用场景


需要根据自身当前状态执行不同方法。

相似状态或者状态机里各个条件中有许多重复代码。将公用代码抽取到抽象基类中来减少重复。


具体实践


状态模式的关键是区分事物内部的状态,内部状态的改变影响事物的行为的改变。

简单举例:

灯亮,按开关,灯灭。

灯暗,按开关,灯亮。

同一个开关按钮,在不同的状态下,表现行为不一样。

// 非状态模式
class Light {
  constructor() {
    this.state = 'off';// 开关状态
    this.button = null;
  }
  init() {
    const btn = document.createElement('button');
    const _this = this;
    btn.innerText = '开关'; 
    this.button = document.body.appendChild(btn);
    this.button.onclick = () => {
      _this.btnPressed()
    }
  }
  btnPressed() {
    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()


如果增加灯光类型,就需要在 btnPressed 方法中不断添加判断。这回造成 btnPressed 需要做的事情太多,也不符合程序设计的开闭原则(需要直接改动 light 类里面的代码)。


通过状态模式改进


使每种状态和它对应的行为之间的关系局部化,这些行为被分散和封装在各自对应的状态类之中,便于阅读和管理代码。

状态之间的切换都被分布在状态类内部,这使得我们无需编写过多的条件分支语言来控制状态之间的转换。

增加新状态也只需要增加一个新的状态类,然后改变状态类之间的切换规则就可以了。

// 将状态类全部抽离
class OffLightState {
  constructor(light) {
    this.light = light
  }
  btnPressed() {
    console.log('弱光')
    this.light.setState(this.light.weakLightState)
  }
}
class WeakLightState {
  constructor(light) {
    this.light = light
  }
  btnPressed() {
    console.log('强光')
    this.light.setState(this.light.strongLightState)
  }
}
class StrongLightState {
  constructor(light) {
    this.light = light
  }
  btnPressed() {
    console.log('关灯')
    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.button = null
  }
  init() {
    const btn = document.createElement('button');
    const _this = this;
    btn.innerText = '开关';
    this.button = document.body.appendChild(btn);
    this.curState = this.offLightState;
    this.button.onclick = () => {
      _this.curState.btnPressed()
    }
  }
  setState(newState) {
    this.curState = newState
  }
  btnPressed(){
    throw new Error('btnPressed 必须被重写')
  }
}
const light = new Light()
light.init()

结构看上去与策略模式相似,不同点在于:

  • 状态之间是知道有其他状态存在的,且能触发从一个状态到另一个状态。
  • 策略则完全不知道其他策略的存在。

状态可被视为策略的扩展。两者都基于组合机制:通过将部分工作委派给 “帮手” 对象来改变其在不同情景下的行为。

参考资料

JS设计模式 状态模式

设计模式之美 状态模式

refactoringguru state

目录
相关文章
|
前端开发
uView Tabs 标签页
uView Tabs 标签页
387 0
|
JavaScript
uniapp+vue3路由跳转传参
uniapp+vue3路由跳转传参
618 0
|
索引
UniApp 组件 u-tabs 详细讲解
UniApp 组件 u-tabs 详细讲解
2777 1
|
存储 Web App开发 消息中间件
原来10张图就可以搞懂分布式链路追踪系统原理
原来10张图就可以搞懂分布式链路追踪系统原理
原来10张图就可以搞懂分布式链路追踪系统原理
|
6月前
|
Kubernetes Cloud Native 调度
《分布式任务调度框架深度对比:Quartz/XXL-JOB/Elastic-Job/PowerJob选型指南》​
根据IDC预测,到2025年全球将有75%的企业任务调度系统需要重构以适应云原生架构。技术雷达监测:定期关注CNCF技术趋势报告渐进式改造:从非核心业务开始验证新框架人才储备:重点培养具备K8s Operator开发能力的调度专家评估现有系统的云原生适配度在测试环境部署PowerJob 4.3.3参与CNCF调度技术社区讨论制定6个月框架迁移路线图(注:本文数据来自各框架官方路线图、CNCF年度报告及笔者压力测试结果,转载请保留出处)
1245 0
|
监控 Linux 应用服务中间件
在Linux中,如何配置负载均衡器?
在Linux中,如何配置负载均衡器?
|
JavaScript 前端开发 程序员
Vue条件语句中v-if、v-else、v-else-if的用法
这篇文章详细介绍了Vue中`v-if`、`v-else`和`v-else-if`条件语句的用法,包括它们的正确使用方式、常见的错误以及如何使用`<template>`标签来同时切换多个元素的显示状态。
|
Prometheus Cloud Native Java
OpenTelemetry: 经得起考验的工具
OpenTelemetry: 经得起考验的工具
1165 2
|
安全 Shell 网络安全
基于Vulnhub靶场之DC-3渗透测试过程
Vulhub靶场介绍: [Vulhub](https://vulhub.org/) 是一个专注于安全漏洞复现和学习的开源项目。它提供了各种常见漏洞的复现环境,帮助网络安全从业者学习和研究漏洞利用技术。这些环境涵盖了Web应用、容器和操作系统等多个领域。Vulhub 的特点包括: 1. **丰富的漏洞场景**:覆盖多种常见的漏洞,如SQL注入、XSS等。 2. **详细复现指南**:为每个漏洞场景提供详细的环境搭建和利用步骤,便于学习和实践。 3. **易于使用**:提供一键部署或Docker镜像,简化环境搭建过程 4. **持续更新与维护**:项目在GitHub上开源,不断接收社区的贡献和更新
616 0
|
移动开发 JavaScript 小程序
uView Radio 单选框
uView Radio 单选框
396 0