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

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

  允许一个对象内部状态改变时改变它的行为,对象看起来似乎修改了它的类

问题:

  状态模式和有限状态机紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。而状态判断通常是由比较多的条件判断语句实现(而过多的状态判断会导致我们项目维护变得更加困难,而且还很臃肿),也可以依据当前对象状态选择响应的行为。

解决方案:

 状态模式建议为对象的所有可能状态新建一个类, 然后将所有状态的对应行为抽取到这些类中。
原始对象被称为上下文 (context), 它并不会自行实现所有行为, 而是会保存一个指向表示当前状态的状态对象的引用, 且将所有与状态相关的工作委派给该对象。
文档将工作委派给一个状态对象文档将工作委派给一个状态对象。如需将上下文转换为另外一种状态, 则需将当前活动的状态对象替换为另外一个代表新状态的对象。 采用这种方式是有前提的: 所有状态类都必须遵循同样的接口, 而且上下文必须仅通过接口与这些对象进行交互。
这个结构可能看上去与策略模式相似, 但有一个关键性的不同——在状态模式中, 特定状态知道其他所有状态的存在, 且能触发从一个状态到另一个状态的转换; 策略则几乎完全不知道其他策略的存在。

状态模式结构和其角色

 在 Java 语言中, 状态模式通常被用于将基于 switch语句的大型状态机转换为对象。
这里是核心 Java 程序库中一些状态模式的示例:
javax.faces.lifecycle.LifeCycle#execute() (由Faces­Servlet控制: 行为依赖于当前 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...

状态模式适合应用场景

  1.  如果对象需要根据自身当前状态进行不同行为, 同时状态的数量非常多且与状态相关的代码会频繁变更的话, 可使用状态模式。
  2.  模式建议你将所有特定于状态的代码抽取到一组独立的类中。 这样一来, 你可以在独立于其他状态的情况下添加新状态或修改已有状态, 从而减少维护成本。
  3.  如果某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时, 可使用该模式。
  4.  状态模式会将这些条件语句的分支抽取到相应状态类的方法中。 同时, 你还可以清除主要类中与特定状态相关的临时成员变量和帮手方法代码。
  5.  当相似状态和基于条件的状态机转换中存在许多重复代码时, 可使用状态模式。
  6.  状态模式让你能够生成状态类层次结构, 通过将公用代码抽取到抽象基类中来减少重复。 

如果状态机只有很少的几个状态, 或者很少发生改变,则无需使用此模型。 

相关文章:

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

允许一个对象内部状态改变时改变它的行为&#xff0c;对象看起来似乎修改了它的类 问题&#xff1a; 状态模式和有限状态机紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中&#xff0c; 程序的行为都不相同&#xff0c; 且可瞬间从一个…...

c语言中的文件操作(2)

文件的打开-fopen 函数介绍 文件的打开方式 相对路径与绝对路径 文件关闭函数fclose 文件操作的正确流程 函数的介绍 文件的打开形式 相对路径与绝对路径 文件的关闭函数-fclose 正确的文件操作的流程 前言 通过前面的章节我们已经知道文件的基本的概念&#xff0c;我们如…...

【Verilog】case、casex、casez的区别

在case语句中&#xff0c;敏感表达式中与各项值之间的比较是一种全等比较&#xff0c;每一位都相同才认为匹配。 在casez语句中&#xff0c;如果分支表达式某些位的值为高阻z&#xff0c;那么对这些位的比较就会忽略&#xff0c;不予考虑&#xff0c;而只关注其他位的比较结果…...

Seata源码笔记(二)

Seata源码笔记&#xff08;二&#xff09; 配置相关的ConfigurationFactory静态代码块load()&#xff1a;融入spring获取value的方式Configuration的get方法拦截后&#xff0c;value取值优先级ObjectHolderPROPERTY_BEAN_MAP getInstancebuildConfiguration reload 基于incubar…...

【Java SE】接口类型

在 Java 中&#xff0c;接口&#xff08;Interface&#xff09;是一种引用类型&#xff0c;类似于特殊的抽象类&#xff0c;用于定义一组方法规范&#xff0c;而不提供具体的实现。接口可以包含成员属性&#xff0c;这些属性默认是常量。尽管每个类只能继承一个父类&#xff0c…...

[代码随想录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.用栈实现队列 这个定义入栈和出栈&#xff0c;往队列中加入…...

redis:RDB和AOF机制

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言RDBAOF总结 前言 redis是一个内存数据库&#xff0c;把数据存储在内存中的&#xff0c;而内存中的数据是不持久的&#xff0c;要想能够做…...

券商隔夜单自动下单交易接口

之前研究打板排板&#xff0c;研究怎么才能买得进去。 最近遇到几只利空跌停板&#xff0c;缩量跌停&#xff0c;明天大概率继续一字封板跌停。 如果卖不掉&#xff0c;意味着还要继续吃几个跌停&#xff0c;甚至ST票十几个跌停都有可能。 一次跌停亏几万&#xff0c;还是挺…...

生成任意3D和4D场景!GenXD:通用3D-4D联合生成框架 | 新加坡国立微软

文章链接: https://arxiv.org/pdf/2411.02319 项目链接&#xff1a;https://gen-x-d.github.io/ 有视频 亮点直击 设计了一个数据整理流程&#xff0c;从视频中获取包含可移动物体的高质量4D数据&#xff0c;并为30,000个视频标注了相机姿态。这个大规模数据集称为CamVid-30K&…...

通过命令学习k8s

1、kubectl 命令可以列出所有命令 2、kubectl version 命令可以查看版本号 3、kubectl cluster-info命令可以查看集群信息&#xff08;192.168.218.136:6443 即为kube-apiserver的IP和端口。&#xff09; [rootk8s-master ~]# kubectl cluster-info Kubernetes master is run…...

【redis】—— 初识redis(redis基本特征、应用场景、以及重大版本说明)

序言 本文将引导读者探索Redis的世界&#xff0c;深入了解其发展历程、丰富特性、常见应用场景、使用技巧等&#xff0c;最后会对Redis演进过程中具有里程碑意义的版本进行详细解读。 &#xff08;一&#xff09;初始redis Redis是一种基于键值对&#xff08;key-value&#x…...

服务器显卡和桌面pc显卡有什么不同

服务器显卡和桌面 PC 显卡在设计目标、性能优化、功能支持和硬件规格上都有显著不同。以下是主要区别&#xff1a; 1. 设计用途 服务器显卡&#xff1a;主要用于计算、深度学习、数据分析、科学计算、虚拟化和图形渲染等任务。其设计目标是持续高负载计算&#xff0c;保证高稳…...

Chrome使用IE内核

Chrome使用IE内核 1.下载扩展程序IE Tab 2.将下载好的IE Tab扩展程序拖拽到扩展程序界面&#xff0c;之后重启chrome浏览器即可...

类和对象(C++)——默认成员函数,构造函数,析构函数

1. 类的默认成员函数 默认成员函数就是用户没有显式实现&#xff0c;编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类&#xff0c;不写的情况下编译器会默认生成以下6个默认成员函数&#xff0c;需要注意的是这6个中最重要的是前4个&#xff0c;最后两个取地址重载&#…...

深入理解 Vue v-model 原理与应用

一、引言 在 Vue.js 开发中,v-model是一个非常重要且强大的指令。它为开发者在处理表单输入和数据双向绑定等场景中提供了极大的便利。无论是新手还是有经验的开发者,深入理解v-model对于高效地构建 Vue 应用至关重要。本文将对v-model进行深入剖析,从其基本原理、使用方式…...

内网域环境、工作组、局域网等探针方案

1. 信息收集 1.1 网络收集 了解当前服务器的计算机基本信息&#xff0c;为后续判断服务器角色&#xff0c;网络环境做准备 systeminfo 详细信息 net start 启动服务 tasklist 进程列表 schtasks 计划任务&#xff08;受权限影响&#xff09; 了解当前服务器的网络接口信息…...

uniapp—android原生插件开发(3Android真机调试)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; 一、打包uniapp资源包&#xff1a; 打包…...

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微控制器设计了一个智能门禁系统&#xff0c;通过集成多个传感器模块和控制设备&#xff0c;实现对门禁系统的自动化管理与控制。该系统能够通过RFID卡、密码输入、以及指纹传感器等多种方式对进出人员进行验证&#xff0c;并结合LCD显示屏提供实时信息反…...

Python学习从0到1 day28 Python 高阶技巧 ⑧ 递归

那就祝我们爬不同的山&#xff0c;还能回到同一条路上&#xff0c;不是时时见面&#xff0c;但是时时惦记之人 —— 24.11.13 递归 1.什么是递归 递归在编程中是一种非常重要的算法 递归&#xff1a;即方法(函数)自己调用自己的一种特殊编程写法 函数调用自己&#xff0c;即…...

高效获取B站视频到本地存储:BilibiliDown工具全攻略

高效获取B站视频到本地存储&#xff1a;BilibiliDown工具全攻略 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/bi/…...

MySQL 8.0.34和5.7.43双版本共存安装指南(Windows环境避坑大全)

MySQL 8.0与5.7双版本共存实战&#xff1a;Windows环境全流程避坑指南 1. 版本共存的核心挑战与解决方案 在开发环境中同时运行MySQL 8.0和5.7版本的需求日益普遍——可能是为了兼容旧系统&#xff0c;或是测试应用在不同版本下的表现。但Windows环境下实现双版本共存会遇到几个…...

Unpaywall扩展:一键解锁学术论文的终极免费方案

Unpaywall扩展&#xff1a;一键解锁学术论文的终极免费方案 【免费下载链接】unpaywall-extension Firefox/Chrome extension that gives you a link to a free PDF when you view scholarly articles 项目地址: https://gitcode.com/gh_mirrors/un/unpaywall-extension …...

【科研必备】Elsevier Tracker:5分钟搞定学术投稿监控的终极解决方案

【科研必备】Elsevier Tracker&#xff1a;5分钟搞定学术投稿监控的终极解决方案 【免费下载链接】Elsevier-Tracker 项目地址: https://gitcode.com/gh_mirrors/el/Elsevier-Tracker 你是否也曾为了追踪Elsevier期刊的审稿状态而反复刷新页面&#xff1f;每天登录系统…...

别再手动下载了!教你用Python+Schedule库打造个人YouTube视频自动下载工具

Python自动化神器&#xff1a;用Schedule库打造智能视频下载系统 每次手动下载YouTube视频不仅耗时耗力&#xff0c;还容易错过更新。作为Python开发者&#xff0c;我们完全可以用代码解放双手&#xff0c;打造一个全自动的视频下载系统。今天要分享的这套方案&#xff0c;结合…...

企业级母婴商城系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

摘要 随着互联网技术的快速发展和电子商务的普及&#xff0c;母婴用品市场呈现出蓬勃发展的态势。年轻父母对于母婴产品的需求日益多样化&#xff0c;传统的线下零售模式已无法满足其便捷、高效、个性化的购物需求。因此&#xff0c;构建一个功能完善、安全可靠的企业级母婴商城…...

一文读懂:控制界的万能公式——PID算法到底是什么?

一文读懂:控制界的万能公式——PID算法到底是什么? 对于每一位踏入工科大门的学生或是初入职场的工程师来说,在自动控制、机器人、电子工程等领域,有一个名字几乎如影随形——PID算法。从天上飞的四轴无人机,到地上跑的平衡小车;从化工厂里庞大的反应釜,到你家中安静运转…...

别只盯着时钟了!用Vivado的Set_Data_Check搞定FPGA里两个数据信号的时序检查(附工程源码)

FPGA时序约束进阶&#xff1a;用Set_Data_Check精准控制数据信号时序关系 在FPGA设计中&#xff0c;时序约束是确保电路功能正确性的关键环节。大多数工程师对时钟与数据信号之间的setup/hold约束已经驾轻就熟&#xff0c;但当面对两个数据信号之间的时序关系时&#xff0c;却常…...

PHP+MySQL图书管理系统实战:从环境搭建到功能实现的保姆级教程(附完整源码)

PHPMySQL图书管理系统实战&#xff1a;从零构建企业级应用 1. 环境配置与项目初始化 在开始构建图书管理系统之前&#xff0c;我们需要搭建一个稳定的开发环境。不同于传统的独立安装方式&#xff0c;我将推荐使用Docker容器化方案&#xff0c;这能确保开发环境的一致性并避免&…...

HiOmics平台:零代码实现ChIP-Seq数据可视化与深度解析

1. 为什么科研人员需要零代码ChIP-Seq分析工具 做表观遗传学研究的朋友们应该都深有体会&#xff0c;ChIP-Seq数据分析就像一场马拉松——从原始数据清洗、序列比对、peak calling到功能注释&#xff0c;每个环节都需要不同的工具和脚本。我刚开始接触这个领域时&#xff0c;光…...