设计模式-状态模式(State)
允许一个对象内部状态改变时改变它的行为,对象看起来似乎修改了它的类
问题:
状态模式和有限状态机紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。而状态判断通常是由比较多的条件判断语句实现(而过多的状态判断会导致我们项目维护变得更加困难,而且还很臃肿),也可以依据当前对象状态选择响应的行为。
解决方案:
状态模式建议为对象的所有可能状态新建一个类, 然后将所有状态的对应行为抽取到这些类中。
原始对象被称为上下文 (context), 它并不会自行实现所有行为, 而是会保存一个指向表示当前状态的状态对象的引用, 且将所有与状态相关的工作委派给该对象。
文档将工作委派给一个状态对象文档将工作委派给一个状态对象。如需将上下文转换为另外一种状态, 则需将当前活动的状态对象替换为另外一个代表新状态的对象。 采用这种方式是有前提的: 所有状态类都必须遵循同样的接口, 而且上下文必须仅通过接口与这些对象进行交互。
这个结构可能看上去与策略模式相似, 但有一个关键性的不同——在状态模式中, 特定状态知道其他所有状态的存在, 且能触发从一个状态到另一个状态的转换; 策略则几乎完全不知道其他策略的存在。
状态模式结构和其角色

在 Java 语言中, 状态模式通常被用于将基于 switch语句的大型状态机转换为对象。
这里是核心 Java 程序库中一些状态模式的示例:
javax.faces.lifecycle.LifeCycle#execute() (由FacesServlet控制: 行为依赖于当前 JSF 生命周期的阶段 (状态))
识别方法: 状态模式可通过受外部控制且能根据对象状态改变行为的方法来识别。
上代码:
public abstract class State {Player player;State(Player player) {this.player = player;}public abstract String onLock();public abstract String onPlay();public abstract String onNext();public abstract String onPrevious();
}
public class LockedState extends State {LockedState(Player player) {super(player);player.setPlaying(false);}@Overridepublic String onLock() {if (player.isPlaying()) {player.changeState(new ReadyState(player));return "Stop playing";} else {return "Locked...";}}@Overridepublic String onPlay() {player.changeState(new ReadyState(player));return "Ready";}@Overridepublic String onNext() {return "Locked...";}@Overridepublic String onPrevious() {return "Locked...";}
}
public class ReadyState extends State {public ReadyState(Player player) {super(player);}@Overridepublic String onLock() {player.changeState(new LockedState(player));return "Locked...";}@Overridepublic String onPlay() {String action = player.startPlayback();player.changeState(new PlayingState(player));return action;}@Overridepublic String onNext() {return "Locked...";}@Overridepublic String onPrevious() {return "Locked...";}
}
public class Player {private State state;private boolean playing = false;private List<String> playlist = new ArrayList<>();private int currentTrack = 0;public Player() {this.state = new ReadyState(this);setPlaying(true);for (int i = 1; i <= 12; i++) {playlist.add("Track " + i);}}public void changeState(State state) {this.state = state;}public State getState() {return state;}public void setPlaying(boolean playing) {this.playing = playing;}public boolean isPlaying() {return playing;}public String startPlayback() {return "Playing " + playlist.get(currentTrack);}public String nextTrack() {currentTrack++;if (currentTrack > playlist.size() - 1) {currentTrack = 0;}return "Playing " + playlist.get(currentTrack);}public String previousTrack() {currentTrack--;if (currentTrack < 0) {currentTrack = playlist.size() - 1;}return "Playing " + playlist.get(currentTrack);}public void setCurrentTrackAfterStop() {this.currentTrack = 0;}
}
public class Client{private Player player;public Client(Player player){this.player = player;}public void test(){System.out.println( player.getState().onPlay());System.out.println( player.getState().onLock());System.out.println( player.getState().onNext());System.out.println( player.getState().onPrevious());}
}
测试:
public class Demo {public static void main(String[] args) {Player player = new Player();Client client = new Client(player);client.test();}
}
Paused...
Stop playing
Locked...
Locked...
状态模式适合应用场景
- 如果对象需要根据自身当前状态进行不同行为, 同时状态的数量非常多且与状态相关的代码会频繁变更的话, 可使用状态模式。
- 模式建议你将所有特定于状态的代码抽取到一组独立的类中。 这样一来, 你可以在独立于其他状态的情况下添加新状态或修改已有状态, 从而减少维护成本。
- 如果某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时, 可使用该模式。
- 状态模式会将这些条件语句的分支抽取到相应状态类的方法中。 同时, 你还可以清除主要类中与特定状态相关的临时成员变量和帮手方法代码。
- 当相似状态和基于条件的状态机转换中存在许多重复代码时, 可使用状态模式。
- 状态模式让你能够生成状态类层次结构, 通过将公用代码抽取到抽象基类中来减少重复。
如果状态机只有很少的几个状态, 或者很少发生改变,则无需使用此模型。
相关文章:
设计模式-状态模式(State)
允许一个对象内部状态改变时改变它的行为,对象看起来似乎修改了它的类 问题: 状态模式和有限状态机紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个…...
c语言中的文件操作(2)
文件的打开-fopen 函数介绍 文件的打开方式 相对路径与绝对路径 文件关闭函数fclose 文件操作的正确流程 函数的介绍 文件的打开形式 相对路径与绝对路径 文件的关闭函数-fclose 正确的文件操作的流程 前言 通过前面的章节我们已经知道文件的基本的概念,我们如…...
【Verilog】case、casex、casez的区别
在case语句中,敏感表达式中与各项值之间的比较是一种全等比较,每一位都相同才认为匹配。 在casez语句中,如果分支表达式某些位的值为高阻z,那么对这些位的比较就会忽略,不予考虑,而只关注其他位的比较结果…...
Seata源码笔记(二)
Seata源码笔记(二) 配置相关的ConfigurationFactory静态代码块load():融入spring获取value的方式Configuration的get方法拦截后,value取值优先级ObjectHolderPROPERTY_BEAN_MAP getInstancebuildConfiguration reload 基于incubar…...
【Java SE】接口类型
在 Java 中,接口(Interface)是一种引用类型,类似于特殊的抽象类,用于定义一组方法规范,而不提供具体的实现。接口可以包含成员属性,这些属性默认是常量。尽管每个类只能继承一个父类,…...
[代码随想录Day10打卡] 理论基础 232.用栈实现队列 225. 用队列实现栈 20. 有效的括号 1047. 删除字符串中的所有相邻重复项
理论基础 队列先入先出。 栈先入后出。 具体的实现和用法根据语言的不同而不同。 参考的文章 https://programmercarl.com/%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 232.用栈实现队列 这个定义入栈和出栈,往队列中加入…...
redis:RDB和AOF机制
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言RDBAOF总结 前言 redis是一个内存数据库,把数据存储在内存中的,而内存中的数据是不持久的,要想能够做…...
券商隔夜单自动下单交易接口
之前研究打板排板,研究怎么才能买得进去。 最近遇到几只利空跌停板,缩量跌停,明天大概率继续一字封板跌停。 如果卖不掉,意味着还要继续吃几个跌停,甚至ST票十几个跌停都有可能。 一次跌停亏几万,还是挺…...
生成任意3D和4D场景!GenXD:通用3D-4D联合生成框架 | 新加坡国立微软
文章链接: https://arxiv.org/pdf/2411.02319 项目链接:https://gen-x-d.github.io/ 有视频 亮点直击 设计了一个数据整理流程,从视频中获取包含可移动物体的高质量4D数据,并为30,000个视频标注了相机姿态。这个大规模数据集称为CamVid-30K&…...
通过命令学习k8s
1、kubectl 命令可以列出所有命令 2、kubectl version 命令可以查看版本号 3、kubectl cluster-info命令可以查看集群信息(192.168.218.136:6443 即为kube-apiserver的IP和端口。) [rootk8s-master ~]# kubectl cluster-info Kubernetes master is run…...
【redis】—— 初识redis(redis基本特征、应用场景、以及重大版本说明)
序言 本文将引导读者探索Redis的世界,深入了解其发展历程、丰富特性、常见应用场景、使用技巧等,最后会对Redis演进过程中具有里程碑意义的版本进行详细解读。 (一)初始redis Redis是一种基于键值对(key-value&#x…...
服务器显卡和桌面pc显卡有什么不同
服务器显卡和桌面 PC 显卡在设计目标、性能优化、功能支持和硬件规格上都有显著不同。以下是主要区别: 1. 设计用途 服务器显卡:主要用于计算、深度学习、数据分析、科学计算、虚拟化和图形渲染等任务。其设计目标是持续高负载计算,保证高稳…...
Chrome使用IE内核
Chrome使用IE内核 1.下载扩展程序IE Tab 2.将下载好的IE Tab扩展程序拖拽到扩展程序界面,之后重启chrome浏览器即可...
类和对象(C++)——默认成员函数,构造函数,析构函数
1. 类的默认成员函数 默认成员函数就是用户没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类,不写的情况下编译器会默认生成以下6个默认成员函数,需要注意的是这6个中最重要的是前4个,最后两个取地址重载&#…...
深入理解 Vue v-model 原理与应用
一、引言 在 Vue.js 开发中,v-model是一个非常重要且强大的指令。它为开发者在处理表单输入和数据双向绑定等场景中提供了极大的便利。无论是新手还是有经验的开发者,深入理解v-model对于高效地构建 Vue 应用至关重要。本文将对v-model进行深入剖析,从其基本原理、使用方式…...
内网域环境、工作组、局域网等探针方案
1. 信息收集 1.1 网络收集 了解当前服务器的计算机基本信息,为后续判断服务器角色,网络环境做准备 systeminfo 详细信息 net start 启动服务 tasklist 进程列表 schtasks 计划任务(受权限影响) 了解当前服务器的网络接口信息…...
uniapp—android原生插件开发(3Android真机调试)
本篇文章从实战角度出发,将UniApp集成新大陆PDA设备RFID的全过程分为四部曲,涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程,轻松应对安卓原生插件开发与打包需求! 一、打包uniapp资源包: 打包…...
goframe开发一个企业网站 统一返回响应码 18
响应码的logic package returncodeimport ("context""gf_new_web/internal/service""github.com/gogf/gf/v2/errors/gcode""github.com/gogf/gf/v2/frame/g" )type sReturncode struct { }var (insReturncode sReturncode{}…...
基于STM32的智能门禁系统设计
引言 本项目基于STM32微控制器设计了一个智能门禁系统,通过集成多个传感器模块和控制设备,实现对门禁系统的自动化管理与控制。该系统能够通过RFID卡、密码输入、以及指纹传感器等多种方式对进出人员进行验证,并结合LCD显示屏提供实时信息反…...
Python学习从0到1 day28 Python 高阶技巧 ⑧ 递归
那就祝我们爬不同的山,还能回到同一条路上,不是时时见面,但是时时惦记之人 —— 24.11.13 递归 1.什么是递归 递归在编程中是一种非常重要的算法 递归:即方法(函数)自己调用自己的一种特殊编程写法 函数调用自己,即…...
AugmentCode无限续杯插件:突破登录限制的自动化解决方案
AugmentCode无限续杯插件:突破登录限制的自动化解决方案 【免费下载链接】free-augment-code AugmentCode 无限续杯浏览器插件 项目地址: https://gitcode.com/gh_mirrors/fr/free-augment-code 痛点解析:开发者的账户管理困境 在软件开发与测试…...
human-pose-estimation.pytorch:简单而强大的人体姿态估计终极指南
human-pose-estimation.pytorch:简单而强大的人体姿态估计终极指南 【免费下载链接】human-pose-estimation.pytorch The project is an official implement of our ECCV2018 paper "Simple Baselines for Human Pose Estimation and Tracking(https://arxiv.o…...
ED-最优设计实战:如何用Python实现鲁棒实验设计(附完整代码)
ED-最优设计实战:如何用Python实现鲁棒实验设计(附完整代码) 在数据科学和工程领域,实验设计是优化参数估计和模型性能的关键环节。传统D-最优设计虽然经典,但在面对参数不确定性时往往表现不佳。本文将带你深入理解ED…...
如何用轻量级工具解决Windows运行Android应用难题?2024最新6种方案深度测评
如何用轻量级工具解决Windows运行Android应用难题?2024最新6种方案深度测评 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 在数字化办公与娱乐深度融合的今…...
利用MathType公式与GLM-OCR结合实现理科试卷自动批改
利用MathType公式与GLM-OCR结合实现理科试卷自动批改 1. 引言 批改理科试卷,尤其是数学、物理这类包含大量公式和符号的试卷,对老师来说一直是个耗时费力的活儿。一张试卷,既要看文字答案对不对,又要检查复杂的公式推导有没有写…...
神州数码无线网络(AC+AP)实战部署与优化指南
1. 神州数码ACAP无线网络部署前的规划准备 第一次接触神州数码无线网络方案时,我被它简洁的架构设计惊艳到了。AC(无线控制器)AP(接入点)的组网模式,特别适合500-2000平米的中型企业办公环境。但在真正动手…...
Springboot 实现多数据源(PostgreSQL 和 SQL Server)连接
为 HagiCode 添加 GitHub Pages 自动部署支持 本项目早期代号为 PCode,现已正式更名为 HagiCode。本文记录了如何为项目引入自动化静态站点部署能力,让内容发布像喝水一样简单。 背景/引言 在 HagiCode 的开发过程中,我们遇到了一个很现实的问…...
trae中安装mcp报Cannot find package/ERR_MODULE_NOT_FOUND问题
简介 我在trae中安装高德地图的mcp和其他的mcp报出了以下错误,以此记录并分享给大家。 新的改变 node:internal/modules/esm/resolve:204 const resolvedOption FSLegacyMainResolve(pkgPath, packageConfig.main, baseStringified); ^ Error: Cannot find pack…...
Vue3 + FFmpeg.wasm 实战:5分钟搞定浏览器端视频格式转换(附完整代码)
Vue3 FFmpeg.wasm:浏览器端视频处理的革命性方案 当现代Web应用越来越依赖多媒体处理能力时,传统依赖后端转码的方案暴露出明显短板:上传耗时、服务器压力大、隐私数据外流风险。而FFmpeg.wasm的出现彻底改变了这一局面——这个基于WebAssem…...
ZYNQ PS侧DDR3内存配置避坑指南:以ACZ702开发板为例,手把手教你搞定MT41K128M16
ZYNQ PS侧DDR3内存配置实战:从硬件原理到Vivado参数设置全解析 当你第一次拿到ACZ702这样的ZYNQ开发板,准备配置PS侧的DDR3内存时,是否遇到过这样的困惑:为什么在Vivado中找不到DDR管脚约束选项?为什么按照传统FPGA的D…...
