状态模式(State)

状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,使其看起来修改了自身所属的类。其别名为状态对象(Objects for States)。

State is a behavior design pattern that allows an object to change its behavior when its internal state changes,
making it appear to have modified the class it belongs to.

在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。
当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
在UML中可以使用状态图来描述对象状态的变化。

结构设计

Context,上下文类,保存了对于一个Concrete State对象(具体状态对象)的引用,并会将所有与该状态相关的工作委派给它。上下文通过状态接口与状态对象交互。
State,状态基类,接口会声明特定于状态的方法。
Concrete State,具体状态类,会自行实现特定于状态的方法。当多个状态中包含相似代码,可以提供一个封装有部分通用行为的中间抽象类。
状态对象可存储对于上下文对象的反向引用。状态对象可以通过该引用从上下文处获取所需信息,并且能触发状态转移。但这可能会带来对象的循环引用,在实际使用时,要通过对象传参的方式使用。
状态模式类图表示如下:
请添加图片描述

状态模式可能看上去与策略模式相似,但有一个关键性的不同——在状态模式中,特定状态知道其他所有状态的存在,且能触发从一个状态到另一个状态的转换,而策略则几乎完全不知道其他策略的存在。

伪代码实现

接下来将使用代码介绍下状态模式的实现。

// 1、State,状态接口,声明特定于状态的方法
public interface IState {void handle(StateContext context);void doSomething();
}// 2、具体状态类,会自行实现特定于状态的方法,这里特定状态知道其他所有状态的存在,且能触发从一个状态到另一个状态的转换
public class ConcreteStateA implements IState {private static ConcreteStateA state;// 这里的单例实现暂不考虑并发场景public static IState getInstance() {if (state == null) {state = new ConcreteStateA();}return state;}@Overridepublic void handle(StateContext context) {doSomething();context.setCurrentState(ConcreteStateB.getInstance());}@Overridepublic void doSomething() {System.out.println("do some thing in the concrete A instance");}
}
public class ConcreteStateB implements IState {private static ConcreteStateB state;// 这里的单例实现暂不考虑并发场景public static IState getInstance() {if (state == null) {state = new ConcreteStateB();}return state;}@Overridepublic void handle(StateContext context) {doSomething();context.setCurrentState(ConcreteStateA.getInstance());}@Overridepublic void doSomething() {System.out.println("do some thing in the concrete B instance");}
}// 3、状态上下文类,保存了对于一个Concrete State对象(具体状态对象)的引用,并会将所有与该状态相关的工作委派给它。  
// 上下文通过状态接口与状态对象交互。  
public class StateContext {private IState currentState;public StateContext(IState defaultState) {this.currentState = defaultState;}public IState getCurrentState() {return this.currentState;}public void setCurrentState(IState newState) {this.currentState = newState;}public void request() {currentState.handle(this);}
}// 4、客户端
public class StateClient {public void test() {StateContext stateContext = new StateContext(new ConcreteStateA());stateContext.request();stateContext.request();stateContext.request();}
}

适用场景

在以下情况下可以考虑使用状态模式:
(1) 对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可以考虑使用状态模式。
(2) 代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,
使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。
(3) 当相似状态和基于条件的状态机转换中存在许多重复代码时,可考虑使用状态模式。状态模式能够生成状态类层次结构,通过将公用代码抽取到抽象基类中来减少重复。

优缺点

状态模式有以下优点:
(1) 封装了转换规则。调用方无需关心状态转换的实现。
(2) 符合开闭原则。无需修改已有状态类和上下文就能引入新状态。
(3) 符合单一职责原则。将与特定状态相关的代码放在单独的类中。
(4) 消除了可能存在的条件语句。通过消除臃肿的状态机条件语句简化上下文代码。
(5) 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
但是该模式也存在以下缺点:
(1) 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。
(2) 增加系统类和对象的个数。
(3) 实现较为复杂,如果使用不当将导致程序结构和代码的混乱。
(4) 对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

参考

《设计模式 可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著, 李英军, 马晓星等译
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/state.html 状态模式
https://refactoringguru.cn/design-patterns/state 状态模式
https://www.runoob.com/design-pattern/state-pattern.html 状态模式
https://www.cnblogs.com/adamjwh/p/10926952.html 简说设计模式——状态模式

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

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

相关文章

AI五子棋——超强改进版本

AI五子棋的改进版本来啦~~ 我们发现,原版的AI五子棋如果调成4的话,非常之慢!!下面给出原版的链接 AI五子棋(原版本) 因此我对其进行了改进,由于正常人下五子棋不会东下一颗棋,西下…

Flutter Dart语言(05)异步

0 说明 该系列教程主要是为有一定语言基础 C/C的程序员,快速学习一门新语言所采用的方法,属于在C/C基础上扩展新语言的模式。 1 async和await 在Dart语言中,虽然没有像其他语言(如Java、C、Python)中的传统多线程概…

Java怎么手动将对象注入到springboot

在Java中,可以使用Spring的ApplicationContext来手动将对象注入到Spring Boot中。 1. 首先,确保你已经在Spring Boot应用程序中引入了Spring的依赖,比如 spring-boot-starter 。 2. 在你的类中注入ApplicationContext对象: Autowi…

谷歌广告(Google ads)如何投放?新手必看的超全教程

Google是公认的全球最大的搜索引擎,同时,Google还通过旗下的 YouTube、Gmail、Google Play、Android等产品,汇集了海量的海外用户。对于跨境出海商家来说,谷歌广告是提高销售额、提高产品流量、拓展全球市场的重要推广渠道。 那么…

一文走进时序数据库性能测试工具 TSBS

一、背景 在物联网、车联网等时序数据场景中,数据的高速写入能力至关重要,会对产品方案的可用性、可靠性和扩展性产生影响。 以物联网为例,当面临千万甚至上亿设备、平均每个设备采集几十个到几百个指标时,每秒生成的数据将达到…

Docker+Consul+Registrator 实现服务注册与发现

第四阶段 时 间:2023年8月8日 参加人:全班人员 内 容: DockerConsulRegistrator 实现服务注册与发现 目录 一、服务注册中心引言 CAP理论是分布式架构中重要理论: 二、服务注册中心软件 (一)Zoo…

ELK 将数据流转换回常规索引

ELK 将数据流转换回常规索引 现象:创建索引模板是打开了数据流,导致不能创建常规索引,并且手动修改、删除索引模板失败 "reason" : "composable template [logs_template] with index patterns [new-pattern*], priority [2…

中国剩余定理的同态性质(CRT变换的同态性)

1、中国剩余定理简介(Chinese Remainder Theory,CRT) 中国剩余定理是关于求解一元线性同余方程组的方法,用形式化的描述就是: m 1 , m 2 , m n m_1,m_2,m_n m1​,m2​,mn​是两两互素的n个整数,有下面的同…

MQTT 订阅接收消息 mosquitto 方式

1 说明 采用 mosquitto 库,实现订阅主题,并接收消息。其中服务器有做限制,需要对应的 cilent id ,cafile 、certfile 、keyfile 等配置2 环境 采用ubuntu 直接编译调试 安装mosquitto 库 sudo apt install libmosquitto-dev su…

chatGLM 本地部署(windows+linux)

chatGLM算是个相对友好的模型,支持中英文双语的对话交流,清华出的 我的教程无需特别的网络设置,不过部分情况因为国内网络速度慢,需要反复重复 chatGLM github地址 一、硬件需求 N卡8G显存以上,最好16G以上&#xff…

【PHP的设计模式】

PHP的设计模式 一、策略模式二、工厂模式三、单例模式四、注册模式五、适配器模式六、观察者模式 一、策略模式 策略模式是对象的行为模式,用意是对一组算法的封装。动态的选择需要的算法并使用。 策略模式指的是程序中涉及决策控制的一种模式。策略模式功能非常强…

vue 使用vue-video-player加载视频

vue 使用vue-video-player加载视频 安装 npm install vue-video-player --savemain.js 引入 import VideoPlayer from "vue-video-player" import "video.js/dist/video-js.css" import "vue-video-player/src/custom-theme.css" import &quo…

SuperMap GIS基础产品桌面GIS FAQ集锦(5)

SuperMap GIS基础产品桌面GIS FAQ集锦(5) 【iDesktop】【iDesktopX】态势推演怎么使用? 【解决办法】 1、要先新建一个CAD数据集,然后将标绘加到CAD数据集中。 2、再使用态势推演管理器,右键新建分组。 3、选中场景中的…

利用ffmpeg分析视频流

ffprobe -show_packets -i "rtsp://192.168.61.46:8554/live?channel0&type0":该命令用于显示 RTSP 流中的数据包信息,例如时间戳、大小、持续时间等。 ffprobe -i "rtsp://192.168.61.46:8554/live?channel0&type0"&…

【算法|数组】手撕经典二分法

算法|数组——二分查找 文章目录 算法|数组——二分查找引言二分查找左闭右闭写法左闭右开写法 总结 引言 首先学习这个算法之前需要了解数组知识:数组。 大概介绍以下: 数组是存储在连续内存空间上的相同类型数据的集合。数组下标都是从0开始。数组在…

数学建模—多元线性回归分析(+lasso回归的操作)

第一部分:回归分析的介绍 定义:回归分析是数据分析中最基础也是最重要的分析工具,绝大多数的数据分析问题,都可以使用回归的思想来解决。回归分析的人数就是,通过研究自变量X和因变量Y的相关关系,尝试去解释…

UML 用例图,类图,时序图,活动图

UML之用例图,类图,时序图,活动图_用例图 时序图_siyan985的博客-CSDN博客 https://www.cnblogs.com/GumpYan/p/14734357.html 用例图与类图 - 简书

webshell链接工具-Godzilla(哥斯拉)

项目地址 https://github.com/BeichenDream/Godzilla

势不可挡!新能源车型L2搭载率破50%,TOP20品牌数据出炉

中国乘用车市场正在走出去年的阴霾。 机构公开数据显示,2023年上半年中国乘用车市场产量1100.77万辆,同比增长7.5%;终端销量959.08万辆,同比增长4.7%;乘用车出口152.36万辆,同比增长87.6%。 在实际交付量…

JMeter启动时常见的错误

很多小伙伴在学工具这一块时,安装也是很吃力的一个问题,之前记得有说过怎么安装jmeter这个工具。那么你要启动jmeter的时候,一些粉丝就会碰到如下几个问题。 1.解压下载好的jmeter安装,Windows 平台,双击 jmeter/bin …