设计模式-状态(State)模式

news2024/11/15 4:55:18

目录

开发过程中的一些场景

状态模式的简单介绍

状态模式UML类图

类图讲解

适用场景

Java中的例子

案例讲解

什么是状态机

如何实现状态机

SpringBoot状态自动机

优点

缺点

与其他模式的区别

小结


  • 开发过程中的一些场景

    • 我们在平时的开发过程中,经常会遇到这样一种情况:就是需要我们处理一个对象的不同状态下的不同行为
    • 比如最常见的就是订单,订单有很多种状态,每种状态又对应着不同的操作,有些操作是相同的,有些操作是不同的
    • 再比如一个音乐播放器程序,在播放器缓冲音乐,播放,暂停,快进,快退,终止等的情况下又对应着各种操作
    • 有些操作在某些情况下是允许的,有些操作是不允许的
    • 还有很多不同的场景,这里就不一一列举了
  • 状态模式的简单介绍

    • 状态模式是行为型设计模式的一种,状态模式允许对象改变它的行为
    • 其设计理念是当对象的内部状态发生改变时,随之改变其行为
    • 状态和行为之间是一一对应的
    • 该模式主要用于,对象的行为依赖于它的状态,并且其行为是随着状态的改变而切换时
    • 这种模式接近于有限状态机的概念
    • 状态模式可以被理解为策略模式,它能够通过调用在模式接口中定义的方法来切换策略
  • 状态模式UML类图

  • 类图讲解

    • State:抽象状态接口(也可以定义成抽象类),该接口封装了所有状态所对应的行为
    • ConcreteStateA/B:具体状态类,该类实现了抽象状态接口,会根据自身对应的状态来实现接口中定义的方法,还有另一个功能是指明如何过渡到下一个状态
    • Context:环境(上下文)角色,该类负责状态的切换,还持有一个State实例,代表当前环境所处状态
  • 适用场景

    • 在以下两种情况下,请使用State模式:
      • 对象的行为取决于它的状态,并且它必须在运行时根据状态更改其行为
      • 根据对象状态的不同,操作有大量的条件语句;此状态通常由一个或多个枚举常量表示;通常,几个操作将包含此相同的条件结构;状态模式把条件语句的分支分别放入单独的类中;这样一来,你就可以将对象的状态视为独立的对象,该对象可以独立于其他对象而变化
  • Java中的例子

    • javax.faces.lifecycle.Lifecycle#execute() 方法由 FacesServlet 控制,其行为取决于当前生命周期阶段
  • 案例讲解

    • 场景:
      • 大家的热情直接影响up的更新频率,那么此时事件和状态就出现了:
        • 事件:投币,点赞,收藏
        • 状态:SOMETIME(想起来什么时候更新就什么时候更新),OFTEN(会经常更新下),USUALLY(有事也更新),ALWAYS(没停过的肝)
      • 我们可以得到一个关系:
        • 投币:UpSometimeState -> UpOftenState
        • 点赞:UpOftenState -> UpUsuallyState
        • 收藏:UpUsuallyState -> UpAlwaysState
        • 英文频率从低到高:Sometime -> Often -> Usually -> Always
    • 代码:
      • 我们先定义一个状态的抽象类,用来表示up的更新频率

      • 接着我们定义子类,分别表示每个不同的状态:

      • 我们还需要一个上下文环境来进行状态的流转关联

      • 接着我们写一个客户端来模拟调用流程:

    • 此时,状态模式便完成了,可以看到我们没有用到if else,便完成了判断
    • 每个状态也是由一个类来代替的,我们对其中一个状态进行的改动,不会影响其他的状态逻辑
    • 通过这样的方式,很好的实现了对扩展开放,对修改关闭的原则
    • 我们看下输出:

  • 什么是状态机

    • 定义:
      • 有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件
    • 要素:
      • 现态:是指当前所处的状态
      • 条件:又称为“事件”;当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移
      • 动作:条件满足后执行的动作;动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态;动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态
      • 次态:条件满足后要迁往的新状态;“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了
  • 如何实现状态机

    • 实现状态机主要体现在两部分:
      • 画出状态转换图和将有限状态机用代码实现
    • 其中代码实现部分其实就是状态模式的实现
    • 画出状态转换图
      • 找出所有状态(圆圈表示)
      • 找出所有状态间的转换条件(圆圈间的线段表示)
      • 分析每个状态需要执行的策略(圆圈边的大括号表示)
    • 将有限状态机用代码实现
      • 定义一个状态机类
      • 根据状态转换图的状态节点(圆圈)**,定义状态**(可使用类(推荐),枚举或无符号整数)
      • 根据状态转换图的转换条件(边)**,实现转换动作**方法
  • SpringBoot状态自动机

    • 完全能结合spring强大的IOC和AOP,实现一个状态自动机
    • 还是刚刚的场景,我们通过Spring StateMachine来实现下
    • 代码
      • 包的引入:

      • 定义状态和事件枚举

      • 创建状态机配置类

      • 注解监听器

      • 创建应用Controller来完成流程

    • 说明
    • 我们可以对如何使用Spring StateMachine做如下小结:
      • 定义状态和事件枚举
      • 为状态机定义使用的所有状态以及初始状态
      • 为状态机定义状态的迁移动作
      • 为状态机指定监听处理器
  • 优点

    • 结构清晰:
      • 状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”
    • 将状态转换显示化,减少对象间的相互依赖:
      • 将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖
    • 状态类职责明确,有利于程序的扩展:
      • 通过定义新的子类很容易地增加新的状态和转换
  • 缺点

    • 状态模式的使用必然会增加系统的类与对象的个数
    • 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱
    • 状态模式对开闭原则的支持并不太好:
      • 对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码
  • 与其他模式的区别

    • 状态模式与策略模式看起来像双胞胎,但他们还是不相同的

  • 小结

    • 状态模式的核心是封装,将状态以及状态转换逻辑封装到类的内部来实现,也很好的体现了“开闭原则”和“单一职责原则”
    • 每一个状态都是一个子类,不管是修改还是增加状态,只需要修改或者增加一个子类即可
    • 在我们的应用场景中,状态数量以及状态转换远比上述例子复杂,通过“状态模式”避免了大量的if-else代码,让我们的逻辑变得更加清晰
    • 同时由于状态模式的良好的封装性以及遵循的设计原则,让我们在复杂的业务场景中,能够游刃有余地管理各个状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1312768.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ Qt开发:ProgressBar进度条组件

Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍ProgressBar进度条组件的常用方法及灵活运用。…

SpringBoot配置mysql加密之Druid方式

一、导入Druid依赖 <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.22</version> </dependency>二、生成密文 方式1. 找到存放druid jar包的目录 1-1、在目录…

EasyExcel处理表头的缓存设置

在学习EasyExcel 时会发现针对使用类模型配置表头相关属性时&#xff0c;EasyExcel 会使用到缓存技术以提升表头的解析速度如下代码&#xff1a; 这些参数再何时设置的哪&#xff1f; 在easyExcel 基础参数设置中会有这个参数filedCacheLocation 。默认采用的使用线程级别的…

MVVM前端设计模式的发展与应用

在MVC模式中&#xff0c;随着代码量越来越大&#xff0c;Controller主要用来处理各种逻辑和数据转化的Controller首当其冲&#xff0c;变得非常庞大&#xff0c;MVC的简写变成了Massive-View-Controller&#xff08;意为沉重的Controller&#xff09; 我曾经接手老项目&#x…

什么是rocketmq❓

在大规模分布式系统中&#xff0c;各个服务之间的通信是至关重要的&#xff0c;而RocketMQ作为一款分布式消息中间件&#xff0c;为解决这一问题提供了强大的解决方案。本文将深入探讨RocketMQ的基本概念、用途&#xff0c;以及在实际分布式系统中的作用&#xff0c;并对Produc…

CBTC上海新能源锂电池展览会奋战华东!2024携手共赢!

2024CBTC上海新能源锂电池技术展览会|上海锂离子电池生产设备展览会 时 间&#xff1a;2024年7月24&#xff5e;26日 地 点&#xff1a;国家会展中心&#xff08;上海虹桥&#xff09; 发展前景&#xff1a; 随着科技的不断进步&#xff0c;锂电池市场逐渐成为全球能源市场的…

GD32f103系列教程—(SPI DMA方式软件实现篇)

DMA知识简介: DMA 控制器提供了一种硬件的方式在外设和存储器之间或者存储器和存储器之间传输数据&#xff0c;而无需 CPU 的介入&#xff0c;从而使 CPU 可以专注在处理其他系统功能上。 项目中需要采用DMA方式传输数据的原因&#xff1a;如果仅仅采用SPI接口进行寄存器通信&…

vue2项目vue-qrcode-reader 扫一扫二维码插件

vue2项目 vue-qrcode-reader 扫一扫二维码插件 问题所在解决办法成功展示 问题所在 今天在引导师弟做扫二维码功能&#xff0c;发现通过npm install --save vue-qrcode-reade安装死活就是报错TypeError: Object...) is not a function 解决办法 百度了很多大牛的博客&#…

【深度学习目标检测】三、基于深度学习的人物摔倒检测(python,yolov8)

深度学习目标检测方法则是利用深度神经网络模型进行目标检测&#xff0c;主要有以下几种&#xff1a; R-CNN系列&#xff1a;包括R-CNN、Fast R-CNN、Faster R-CNN等&#xff0c;通过候选区域法生成候选目标区域&#xff0c;然后使用卷积神经网络提取特征&#xff0c;并通过分类…

【高效开发工具系列】DataGrip入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

数据分享 I 全国市级商品房屋销售数据,shp/excel格式,2005-2020年数据

基本信息. 数据名称: 全国市级商品房屋销售数据 数据格式: Shp、excel 数据时间: 2005-2020年 数据几何类型: 面 数据坐标系: WGS84坐标系 数据来源&#xff1a;网络公开数据 数据字段&#xff1a; 序号字段名称字段说明1spxse商品房销售额&#xff08;亿元&#xf…

主卧卫生间门对着床,怎么设计才能让你好好睡觉呢?福州中宅装饰,福州装修

主卧卫生间门对着床&#xff0c;一抬眼就能和卫生间来一个对视&#xff0c;心里很膈应&#xff0c;那么怎么解决这个问题呢&#xff1f; 1️⃣门改方向 首先&#xff0c;你可以考虑把卫生间门的开门方向改一下。如果卫生间门是向外开的&#xff0c;你可以考虑把门换成向内开的…

吴恩达《机器学习》12-4-12-5:核函数 1、核函数 2

一、核函数 1 1. 多项式模型的局限性 在之前的学习中&#xff0c;了解到可以使用多项式模型来解决无法用直线进行分隔的分类问题。例如&#xff0c;对于判定边界的建模&#xff0c;可能会使用类似于以下形式的模型&#xff1a; 然而&#xff0c;这样的多项式模型在实际应用中…

ALV动态GUI标题

导语&#xff1a;快两个月没有分享内容了&#xff0c;积攒了一大堆&#xff0c;最近经历了一些变动&#xff0c;有些充实和忙碌&#xff0c;最近在做的客制化平台中&#xff0c;顾问需要在不同的按钮对应的ALV中&#xff0c;展示不同的GUI标题。 效果图&#xff1a; 实现方法&a…

大模型概述

文章目录 大模型语言大模型视觉大模型多模态大模型 大模型 所谓 大&#xff1a;模型结构大&#xff0c; 参数量大&#xff0c;训练数据量大 大模型包含数十亿个参数&#xff0c;模型大小可以达到数百GB甚至更大。这种巨大的模型规模为其提供了强大的表达能力和学习能力多任务…

网络安全——SQL注入实验

一、实验目的要求&#xff1a; 二、实验设备与环境&#xff1a; 三、实验原理&#xff1a; 四、实验步骤&#xff1a; 五、实验现象、结果记录及整理&#xff1a; 六、分析讨论与思考题解答&#xff1a; 七、实验截图&#xff1a; 一、实验目的要求&#xff1a; 1、…

【DC-DC】世微 AP9166 降压恒压芯片 18V 2A同步降压转换器

600KHz&#xff0c;18V&#xff0c;2A同步降压转换器 概述 AP9166是一款完全集成的效率2A同步整流降压转换器。AP9166运行在宽输出电流上以高效率 负载范围。此设备提供两个操作模式、PWM控制和PFM模式切换控制&#xff0c;允许更宽范围的高效率 负载AP9166至少需要现成标准的…

亲测好用的国内AI绘画工具TOP榜,中文输入,新手友好!

“如果不想被AI工具替代&#xff0c;那就先成为用好工具的人。” 最近AI绘画也是大火&#xff0c;上次给大家整理了9款国内实用的AI工具&#xff0c;很多小伙伴就私信我能不能整理一下关于国内可用的AI绘画工具&#xff0c;因为现在最火的AI绘画工具Midjourney和Stable Diffus…

换内核ubuntu

grep menuentry /boot/grub/grub.cfg我要使用第三个(索引从0开始&#xff0c;所以是第二个) 可以使用vi编辑&#xff08;很麻烦&#xff09; i变为插入模型 esc变为普通模型 &#xff1a;x删除单个字符&#xff0c;dd删除一行&#xff0c;&#xff1a;wq保存并退出 更新文件…

ArkTS 任务统计页面

我们继续学习使用ArkTS实现一个任务进度的统计功能。 1.公共的组件、样式 class Task{static id: number 1// 任务名称name: string 任务${Task.id}// 任务状态: 是否完成finished: boolean false }// 统计的卡片样式 Styles function card(){.width(95%).padding(20).backg…