22、设计模式之状态模式(State)

一、什么是状态模式
状态模式是一种行为型设计模式。它允许对象在内部状态发生改变时改变它的行为,简单地讲就是,一个拥有状态的context对象,在不同状态下,其行为会发生改变。

二、角色组成

上下文(Context):定义客户端需要的接口,并且负责具体状态的切换。
抽象状态(Abstract State):抽象状态类是所有具体状态类的基类或接口。负责定义该状态下的行为,可以一个或多个。
具体状态(Concrete State):具体状态类实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。

三、 优缺点
优点:

客户端只需要与上下文对象进行交互,而不需要了解具体状态对象的切换和行为实现细节。
状态模式遵循开闭原则,使系统更加可扩展。当需要增加新的状态时,只需添加新的具体状态类,而无需修改上下文对象或其他状态类。
避免了使用大量的条件语句来控制对象在不同状态下的行为。它将状态相关的代码分散到各个具体状态类中,使代码更加清晰、可读性更高,易于维护和扩展。
状态转换被封装在具体状态类中,可根据需求定义不同的状态切换规则,使得状态转换过程可控、灵活。
缺点:

状态模式增加了系统中类的数量,引入了更多的类,可能会增加代码的复杂性。
对于简单、直接的状态机,使用状态模式可能会显得过于繁琐,增加了代码的冗余。在这种情况下,可以采用简化的条件语句来处理状态转换。
四、应用场景
4.1 生活场景
自动售货机:自动售货机中的商品状态会随着库存量的变化而改变。当库存为0时,商品状态为"售罄";当库存充足时,商品状态为"可购买";
购物车状态:在线购物网站中,购物车可以有不同的状态,比如空、有商品、结算中等。每个状态下,购物车的显示内容和可用操作不同。

4.2 java场景

Thread类:线程有new、Runnable、Blocked、Waiting、Time_Waiting和Terminated状态。这些状态代表了线程在不同的执行阶段或操作中的不同状态。Thread类内部使用了状态模式来管理和切换线程的状态。
Connection接口:Connection接口表示与数据库的连接,它可能处于不同的状态,比如打开、关闭、空闲、繁忙等。Connection接口在不同的状态下提供了不同的操作方法,以便与数据库进行交互。

五、代码实现
下面以自动售卖机为例,解释一下状态模式。我们可以将售卖机分为三个部分:自动售卖机(Machine)类作为上下文(Context),状态(State)作为状态的抽象状态(Abstract State),售卖机的三个状态——未投币(NoCoinState)、已投币(HasCoinState)、出售中(SlodState)作为具体状态(Concrete State)

5.0 UML类图
在这里插入图片描述
5.1 State——抽象状态

/**** 1.抽象状态(Abstract State):状态接口* 定义:定义该状态下的行为,可以一个或多个。*/
public interface State {//投币void insertCoin();//选择商品void selectProduct();//发放商品void dispense();
}

5.2 具体状态

/*** * 2.具体状态(Concrete State):未投币状态* 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。*/
public class NoCoinState implements State{private Machine machine;public NoCoinState(Machine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("已投币");// 切换到已投币状态machine.setState(machine.getHasCoinState());}@Overridepublic void selectProduct() {System.out.println("请先投币");}@Overridepublic void dispense() {System.out.println("请先投币选择商品");}
}
/*** * 2.具体状态(Concrete State):已投币状态* 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。*/
public class HasCoinState implements State{private Machine machine;public HasCoinState(Machine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("已投币,请勿重复投币");}@Overridepublic void selectProduct() {System.out.println("商品已选择");// 切换到出售状态machine.setState(machine.getSoldState());}@Overridepublic void dispense() {System.out.println("请先选择商品");}
}
/**** 2.具体状态(Concrete State):出售状态* 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。*/
public class SoldState implements State{private Machine machine;public SoldState(Machine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("正在出售商品,请稍等");}@Overridepublic void selectProduct() {System.out.println("正在出售商品,请稍等");}@Overridepublic void dispense() {System.out.println("商品已发放");//切换到未投币状态machine.setState(machine.getNoCoinState());}
}

5.3 Machine——上下文

/** * 3.上下文(Context):自动售卖机* 定义:定义客户端需要的接口,并且负责具体状态的切换。*/
public class Machine {//未投币状态private State noCoinState;//已投币状态private State hasCoinState;//出售状态private State soldState;//当前状态private State currentState;public Machine() {noCoinState = new NoCoinState(this);hasCoinState = new HasCoinState(this);soldState = new SoldState(this);currentState = noCoinState; // 初始状态为未投币状态}public void setState(State state) {currentState = state;}public State getNoCoinState() {return noCoinState;}public State getHasCoinState() {return hasCoinState;}public State getSoldState() {return soldState;}public void insertCoin() {currentState.insertCoin();}public void selectProduct() {currentState.selectProduct();}public void dispense() {currentState.dispense();}
}

5.4 testState

/**** 状态模式测试类*/
@SpringBootTest
public class TestState {@Testvoid testState(){//创建上下文对象(自动售卖机)Machine machine = new Machine();System.out.println("=======直接选择商品=======");machine.selectProduct();System.out.println("======投币--->选择商品--->发放商品=======");machine.insertCoin();machine.selectProduct();machine.dispense();System.out.println("=======投币--->发放商品=======");machine.insertCoin();machine.dispense();}
}

在这里插入图片描述
六、总结
熟悉策略模式的小伙伴可能会发现,状态模式和策略模式的UML类图几乎一摸一样,但这两中模式的应用场景是不一样的。策略模式的多种算法行为选择一种就能满足,彼此之间是独立的;而状态模式中各个状态间存在相互关系,彼此之间在一定条件下存在自动切换状态的效果,并且用户不能指定状态,只能设置初始状态。

以下情况出现,可以考虑状态模式:

当一个对象的行为取决于其内部状态,并且在不同状态下具有不同的行为时
当对象的行为在运行时需要根据其状态动态改变,并且需要避免大量的条件语句和分支判断时。
当代码中存在大量的条件语句和分支逻辑,并且这些逻辑与对象的状态变化相关时。
当对象的状态之间存在复杂的转换关系,并且需要维护状态转换的一致性时。

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

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

相关文章

【Leetcode-54.螺旋矩阵】

题目: 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]示例 2: 输入&#xff1…

从单机到分布式微服务,大文件校验上传的通用解决方案

一、先说结论 本文将结合我的工作实战经历,总结和提炼一种从单体架构到分布式微服务都适用的一种文件上传和校验的通用解决方案,形成一个完整的方法论。本文主要解决手段包括多线程、设计模式、分而治之、MapReduce等,虽然文中使用的编程语言…

外包干了3个月,技术明显进步。。。。。

在湖南的一个安静角落,我,一个普通的大专生,开始了我的软件测试之旅。四年的外包生涯,让我在舒适区里逐渐失去了锐气,技术停滞不前,仿佛被时间遗忘。然而,生活的转机总是在不经意间降临。 与女…

VMware安装Centos 7系统+设置共享文件夹+VMware Tools安装

文章目录 镜像下载地址下载页自己选择直接点击下边url下载 VMware环境1.新建虚拟机2.选择“自定义(高级)”,并点击【下一步】3.选择虚拟机硬件兼容性,并点击【下一步】4.选择“稍后安装操作系统”,并点击【下一步】5.选择操作系统版本&#x…

阿里云服务器地域怎么选?地域选择经验分享

阿里云服务器地域选择方法,如何选择速度更快、网络延迟更低的地域节点,地域指云服务器所在的地理位置区域,地域以城市划分,如北京、杭州、深圳及上海等,如何选择地域?建议根据用户所在地区就近选择地域&…

如何将大华dav视频转mp4?一键无损清晰转换~

Digital Audio Video(DAV)文件格式源于数字监控领域,旨在解决视频监控数据的存储和回放问题。随着数字监控技术的发展,DAV格式逐渐成为监控设备记录视频的标准格式,广泛应用于安防系统、摄像头监控等场景。 MP4文件格式…

掌握微服务性能监控:走向高效稳定的系统之路

掌握微服务性能监控:走向高效稳定的系统之路 一、微服务性能监控的挑战二、性能监控的目标与指标三、性能监控工具概览四、实践案例分析五、结语 大家好,这里是程序猿代码之路,在当今快速迭代和发布的软件开发周期中,微服务架构以…

付费代理IP与免费代理IP的区别

目录 一、稳定性与可用性 二、速度与性能 三、安全性与隐私保护 四、功能与服务 五、案例与代码示例 六、总结 在网络爬虫、数据分析、网络安全测试等场景中,代理IP的使用是非常普遍的。代理IP能够帮助用户隐藏真实IP地址,突破地域限制&#xff0c…

6个选品建议,改善你的亚马逊现状。

一、市场热点与需求调研 深入研究当前市场趋势,了解消费者需求的变化。使用亚马逊的销售数据、评价、问答等功能,以及第三方市场研究工具,比如店雷达,分析潜在热销产品的特点。注意季节性需求,提前布局相关选品&#…

【数据挖掘】练习2:数据管理1

课后作业2&#xff1a;数据管理1 一&#xff1a;上机实验1 # 读入数据 data("CO2") # 查看数据集CO2中的变量名称&#xff0c;并将变量Treatment的名称更改为Treat names(CO2) names(CO2)[names(CO2) "Treatment"] <- "Treat" names(CO2)…

login登录界面

展示情况 代码&#xff1a; <template><div class"wrapper"><div style"margin: 200px auto; background-color: #fff; width: 350px; height: 300px; padding: 20px; border-radius: 10px"> <div style"margin: 20px 0; text…

C语言实现一个两个数加减乘除的答题代码(含文件保存),用户增加,题目增加,题目测试,题目答题等等

目录 1、这是我大一自己写的小代码&#xff0c;现在翻到了就分享出来&#xff0c;高手勿喷。 2、项目运行 3、获取完整源码网址 1、这是我大一自己写的小代码&#xff0c;现在翻到了就分享出来&#xff0c;高手勿喷。 2、项目运行 &#xff08;1&#xff09;测试模块 每次…

网安渗透攻击作业(4)

Unload-labs-01 function checkFile() { var file document.getElementsByName(upload_file)[0].value; if (file null || file "") { alert("请选择要上传的文件!"); return false; } //定义允许上传的文件类型 v…

【Linux】对进程PCB的理解查看进程信息的方法

一、学习准备&#xff1a;对操作系统工作模式的理解 首先我们要清楚的是&#xff0c;操作系统是一个进行软硬件资源管理的软件。操作系统对下要管理好底层硬件。每一个硬件的生产产商都会给他们的产品提供对应的驱动程序&#xff0c;驱动程序是特定于某一硬件或系统设备的软件组…

angularjs 指令实现自定义滚动条

场景&#xff1a;横向商品栏&#xff0c;把原有的滚动条改成自定义的样式&#xff0c;并且给两边加上箭头可以调整&#xff0c;可以拖动商品和滚轮实现滚动条效果。 js appService.directive(customScrollbar, function() {return {restrict: A,transclude: true,scope: {ena…

Linux编程4.8 网络编程-建立连接

1、服务器端 #include <sys/types.h> #include <sys/socket.h>int listen(int sockfd, int backlog);返回&#xff1a;成功返回0&#xff0c;出错返回-1。参数&#xff1a;sockfd:套接字的文件描述符backlog:定义了sockfd的挂起连接队列可能增长的最大长度。…

关于udp能跨局域网传输的问题

UDP&#xff08;用户数据报协议&#xff09;以其独特的传输特性在多种应用场景中都有着极其重要的作用。然而&#xff0c;关于UDP是否能跨局域网&#xff08;LAN&#xff09;进行传输&#xff0c;以及这一传输过程中的优缺点&#xff0c;一直是网络技术领域讨论的热点。本文将详…

Unity中PICO中手柄按键返回值

文章目录 前言一、我们看一下每个按键返回值获取按键返回值的方法 二、我们实现一个左摇杆控制平滑移动的功能1、创建一个左摇杆控制移动的脚本2、传入XR Origin对象&#xff0c;并且定义一个公开变量控制移动速度3、获取到摇杆是否移动&#xff0c;以及移动的偏移量4、如果摇杆…

Modeling Influence Diffusion over Signed Social Networks

关键词——社会系统、影响力扩散、建模、签名社交网络、影响力最大化 Abstract 在离线或在线世界中&#xff0c;许多社交系统可以表示为签名社交网络&#xff0c;包括积极和消极关系。尽管由于独特极性特征的巨大应用价值&#xff0c;人们对签名社交网络进行了各种研究&#x…

【Docker篇】自定义Dockerfile的操作

文章目录 &#x1f354;镜像结构&#x1f6f8;什么是Dockerfile⭐基于Ubuntu镜像构建一个新镜像&#xff0c;运行一个java项目&#x1f50e;使用 java:8-alpine &#x1f354;镜像结构 镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。 我们以MySQL为例&am…