Java设计模式:状态模式

❤ 作者主页:欢迎来到我的技术博客😎
❀ 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~*
🍊 如果文章对您有帮助,记得关注点赞收藏评论⭐️⭐️⭐️
📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉

文章目录

  • 一、状态模式的定义
  • 二、未使用状态模式的案例
  • 三、状态模式的结构
  • 四、状态模式的实现
  • 五、状态模式的优缺点
  • 六、状态模式的使用场景
  • 七、状态模式和策略模式的区别

一、状态模式的定义

状态模式(State Pattern)是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。该模式将对象的行为封装在不同的状态类中,使得在不同状态下可以选择不同的行为,从而使对象看起来好像修改了其类。


二、未使用状态模式的案例

在引入状态模式之前,我们先来演示一下没有使用状态模式的业务场景。

业务:在一个车辆租赁应用中,车辆的状态有四种:可租用、已出租、维修中、已归还。现在要实现进行车辆状态之间状态的互相切换,每一种状态改变,都有可能要根据其他状态来更新处理。例如,如果车辆处于可租用状态,则可以执行出租、维修状态,如果车辆处于维修状态,则可以执行可出租、归还操作。

类图如下:
在这里插入图片描述
 

具体的类设计如下:

车辆租赁接口类:

public interface ICarRent {//车辆的4种状态public final static int AvailableState = 1; //可租用状态public final static int RentedState = 2; //已出租状态public final static int InServiceState = 3; //维修中状态public final static int ReturnedState = 4; //已归还状态//设置车辆的状态public void setState(int state);//车辆的动作public void Available();public void Rented();public void InService();public void Returned();}

车辆租赁接口实现类:

public class CarRent implements ICarRent {private int state;@Overridepublic void setState(int state) {this.state = state;}//执行可租用动作@Overridepublic void Available() {switch (this.state) {case AvailableState :System.out.println("车辆无法重复处于可租用状态");break;case RentedState :System.out.println("车辆已出租");this.setState(RentedState); //将车辆的状态由可租用变成已出租break;case InServiceState :System.out.println("车辆处于维修中");this.setState(InServiceState);break;case ReturnedState :System.out.println("车辆无法处于已归还状态");break;}}//执行已出租动作@Overridepublic void Rented() {switch (this.state) {case AvailableState :System.out.println("车辆无法处于可租用状态");break;case RentedState :System.out.println("车辆无法重复处于已租用状态");break;case InServiceState :System.out.println("车辆处于维修中");this.setState(InServiceState);break;case ReturnedState :System.out.println("车辆已归还");this.setState(ReturnedState);break;}}//执行维修中动作@Overridepublic void InService() {switch (this.state) {case AvailableState :System.out.println("车辆无法处于可租用状态");break;case RentedState :System.out.println("车辆无法处于已租用状态");break;case InServiceState :System.out.println("车辆无法处于重复处于维修状态");break;case ReturnedState :System.out.println("车辆已归还");this.setState(ReturnedState);break;}}//执行已归还动作@Overridepublic void Returned() {switch (this.state) {case AvailableState :System.out.println("车辆可租用");this.setState(AvailableState);break;case RentedState :System.out.println("车辆已出租");this.setState(RentedState); break;case InServiceState :System.out.println("车辆处于维修中");this.setState(InServiceState);break;case ReturnedState :System.out.println("车辆无法重复处于维修状态");break;}}
}

客户端类:

public class client {public static void main(String[] args) {CarRent carRent = new CarRent();carRent.setState(ICarRent.AvailableState);carRent.Available();carRent.Rented();carRent.InService();carRent.Returned();}
}

通过上述代码,我们可以发现已经可以满足业务需求了,但是这种实现方式会存在下面的问题:

  • 使用了大量的 switch...case 这样的逻辑判断(if…else也是一样),使程序的可阅读性很差;
  • 如果新增了新的状态的话,则需要去修改上面的判断逻辑,可扩展很差;

因此,我们可以通过使用 状态模式 就可以很好地解决上述问题。


三、状态模式的结构

状态模式包含以下主要角色:

  • 环境(Context)角色: 也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
  • 抽象状态(State)角色: 定义一个接口,用于封装环境对象中的特定状态所对应的行为。
  • 具体状态(ConCrete State)角色: 实现抽象状态所对应的行为。

四、状态模式的实现

使用状态模式对上述案例进行改造,类图如下:
在这里插入图片描述
 
具体的类设计如下:

抽象状态类:

public abstract class CarState {//声明环境角色类变量protected Context context;public void setContext(Context context) {this.context = context;}//车辆可租用操作public abstract void Available();//车辆已出租操作public abstract void Rented();//车辆维修中操作public abstract void InService();//车辆已归还操作public abstract void Returned();}

车辆可租用状态类:

public class AvailableState extends CarState {@Overridepublic void Available() {System.out.println("车辆无法重复处于可租用状态");}@Overridepublic void Rented() {System.out.println("车辆已出租");super.context.setCarState(Context.RENTED_STATE);super.context.Rented();}@Overridepublic void InService() {System.out.println("车辆处于维修中");super.context.setCarState(Context.IN_SERVICE_STATE);super.context.InService();}@Overridepublic void Returned() {System.out.println("车辆无法处于已归还状态");}
}

车辆已出租状态类:

public class RentedState extends CarState {@Overridepublic void Available() {System.out.println("车辆无法处于可租用状态");}@Overridepublic void Rented() {System.out.println("车辆无法重复处于已租用状态");}@Overridepublic void InService() {System.out.println("车辆处于维修中");super.context.setCarState(Context.IN_SERVICE_STATE);super.context.InService();}@Overridepublic void Returned() {System.out.println("车辆已归还");super.context.setCarState(Context.RETURNED);super.context.Returned();}
}

车辆维修中状态类:

public class InServiceState extends CarState {@Overridepublic void Available() {System.out.println("车辆无法处于可租用状态");}@Overridepublic void Rented() {System.out.println("车辆无法处于已租用状态");}@Overridepublic void InService() {System.out.println("车辆无法处于重复处于维修状态");}@Overridepublic void Returned() {System.out.println("车辆已归还");super.context.setCarState(Context.RETURNED);super.context.Returned();}
}

车辆已归还状态类:

public class Returned extends CarState {@Overridepublic void Available() {System.out.println("车辆可租用");super.context.setCarState(Context.AVAILABLE_STATE);super.context.InService();}@Overridepublic void Rented() {System.out.println("车辆已出租");super.context.setCarState(Context.RENTED_STATE);super.context.Rented();}@Overridepublic void InService() {System.out.println("车辆处于维修中");super.context.setCarState(Context.IN_SERVICE_STATE);super.context.InService();}@Overridepublic void Returned() {System.out.println("车辆无法重复处于维修状态");}
}

环境类:

public class Context {//定义对应状态对象的常量public final static AvailableState AVAILABLE_STATE = new AvailableState();public final static RentedState RENTED_STATE = new RentedState();public final static InServiceState IN_SERVICE_STATE = new InServiceState();public final static Returned RETURNED = new Returned();//定义一个当前车辆状态变量private CarState carState;public CarState getCarState() {return carState;}//设置当前状态对象public void setCarState(CarState carState) {this.carState = carState;//设置当前状态对象中的Context对象this.carState.setContext(this);}public void Available() {this.Available();}public void Rented() {this.Rented();}public void InService() {this.InService();}public void Returned() {this.Returned();}}

客户端类:

public class Client {public static void main(String[] args) {CarRent carRent = new CarRent();carRent.setState(ICarRent.AvailableState);carRent.Available();carRent.Rented();carRent.InService();carRent.Returned();}
}

测试结果:
在这里插入图片描述
 


五、状态模式的优缺点

优点:

  1. 封装性强: 状态模式将每个状态的行为封装在独立的类中,使得每个状态的实现相对独立,提高了代码的封装性。
  2. 可扩展性: 可以方便地添加新的状态类,而不需要修改已有的代码,系统的可扩展性得到提高。
  3. 简化条件判断: 状态模式通过将状态的判断转移到状态类中,避免了大量的条件判断语句,提高了代码的可读性和维护性。
  4. 提高了上下文类的间接性: 上下文类中不再包含复杂的条件判断语句,仅负责委托给当前状态类处理。
  5. 状态切换更灵活: 状态模式使得状态切换变得更加灵活,状态之间的切换由具体的状态类负责,可以在不影响其他状态的情况下单独修改某一状态的行为。

缺点:

  1. 类数量增加: 引入状态模式会增加系统中类的数量,特别是当状态很多时,会导致类的数量呈指数级增长。
  2. 状态切换过多: 如果状态之间的切换比较频繁,可能会导致系统变得复杂难以维护。
  3. 上下文类的状态转换逻辑: 上下文类中的状态转换逻辑可能会分散到各个状态类中,使得理解整个状态转换流程变得复杂。
  4. 不适用于简单的状态: 当系统中的状态很简单,且状态之间的切换较为简单时,引入状态模式可能显得繁琐,不划算。

六、状态模式的使用场景

  1. 对象的行为依赖于其状态,并且在运行时可以改变状态: 当一个对象在不同状态下有不同的行为,并且这些行为可以在运行时动态地改变,状态模式就能够很好地解决这种情况。
  2. 有大量条件语句判断对象的状态: 如果在代码中存在大量的条件语句用于判断对象的状态,并且这些条件语句导致代码复杂且难以维护,那么状态模式可以用于优化代码结构。
  3. 状态切换的逻辑相对复杂: 当状态之间的转换逻辑比较复杂,而且在不同状态下可能有不同的行为,使用状态模式可以将状态转换逻辑封装在状态类中,使代码更加清晰。
  4. 一个对象存在多个状态且状态之间相互转换: 如果一个对象有多个状态,并且这些状态之间存在相互转换的关系,使用状态模式可以更好地管理这种状态转换。
  5. 需要动态添加新状态: 如果系统需要在运行时动态地添加新的状态,并且这些新状态可能导致行为的改变,状态模式可以提供良好的扩展性。
  6. 避免使用过多的条件判断语句: 当需要避免过多的条件判断语句,提高代码的可读性和可维护性时,状态模式可以将状态相关的代码分散到不同的状态类中,使得代码更加清晰。

七、状态模式和策略模式的区别

状态模式和策略模式的UML类图几乎一模一样,容易在初学时混淆。然而,它们有一些相似之处,但也存在着明显的区别。

状态模式(State Pattern):

  1. 关注对象内部状态的改变: 状态模式主要关注对象在不同状态下的行为变化,对象的行为随着内部状态的改变而改变。
  2. 状态切换由上下文控制: 状态模式中,状态的切换是由上下文(Context)类控制的,上下文类维护一个当前状态的引用,并在状态发生改变时委托给相应的状态类。
  3. 状态间有转换关系: 状态模式适用于对象存在多个状态,且这些状态之间存在明确的转换关系。

策略模式(Strategy Pattern):

  1. 关注算法的替换: 策略模式主要关注定义一系列算法,使它们可以互相替换,使得算法的选择可以独立于使用算法的客户端。
  2. 客户端决定使用哪个策略: 策略模式中,客户端决定使用哪个具体策略,客户端持有一个策略接口的引用,而不是持有具体策略类的引用。
  3. 算法间无转换关系: 策略模式适用于需要动态地在多个算法中选择一个的情况,这些算法之间可能没有明确的转换关系。

区别总结:

  1. 关注点不同: 状态模式关注对象在不同状态下的行为变化,而策略模式关注算法的替换和客户端如何选择使用算法。
  2. 状态切换控制: 在状态模式中,状态的切换由上下文控制;而在策略模式中,客户端控制使用哪个策略。
  3. 状态间关系: 状态模式适用于对象存在多个状态且状态间有明确的转换关系;策略模式适用于多个算法可以替换且客户端需要动态选择算法的情况。

 
非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 分享👥 留言💬thanks!!!

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

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

相关文章

天融信TOPSEC Cookie 远程命令执行漏洞

产品介绍 天融信TopSec 安全管理系统,是基于大数据架构,采用多种技术手段收集各类探针设备安全数据,围绕资产、漏洞、攻击、威胁等安全要素进行全面分析,提供统一监测告警、集中策略管控、协同处置流程,实现客户等保合…

GZ075 云计算应用赛题第5套

2023年全国职业院校技能大赛(高职组) “云计算应用”赛项赛卷5 某企业根据自身业务需求,实施数字化转型,规划和建设数字化平台,平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”,拟采用开源OpenSt…

Vue: 多个el-select不能重复选择相同属性

一、场景 1.需求&#xff1a; 用户可自由选择需要修改的对象并同时修改多个属性&#xff0c;需要校验修改对象不能重复选择&#xff0c;但是可供修改属性是固定的 2.目标效果&#xff1a; 二、实现 1.主要代码&#xff1a; <template><el-selectv-model"se…

SV-DJS-I13 深圳锐科达电梯 IP 五方对讲规格书

SV-DJS-I13 深圳锐科达电梯 IP 五方对讲规格书 DJS-I13 是专门对行业用户需求研发的一款 SIP 电梯五方对讲。它不仅有稳定性 好、电信级音质的优点&#xff0c;且完美兼容当下所有基于 SIP 的主流 IPPBX/软交换/IMS 平台, 如 Asterisk, Broadsoft, 3CX, Elastix 等。它集…

redis 三主六从高可用dockerswarm高级版(不固定ip)

redis集群(cluster)笔记 redis 三主三从高可用集群docker swarm redis 三主六从高可用docker(不固定ip) redis 三主六从高可用dockerswarm高级版(不固定ip) 此博客解决&#xff0c;redis加入集群后&#xff0c;是用于停掉后重启&#xff0c;将nodes.conf中的旧的Ip替换为新的…

【C语言进阶篇】 数组常考笔试题万字解析(下)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言&#x1f4ac; 数组笔试题解析&#x1f4ad; 字符数组笔试题✅ 字符数组笔试题解析 &#x1…

印刷企业如何快速上线MES管理系统解决方案

随着科技的不断发展&#xff0c;印刷行业正面临着前所未有的挑战与机遇。为了提高生产效率、降低成本、提升企业竞争力&#xff0c;许多印刷企业开始引入MES管理系统解决方案。然而&#xff0c;对于很多企业来说&#xff0c;如何快速、有效地上线MES管理系统却是一个难题。本文…

工作流自动化:它是什么,常见示例以及如何实现

由于您的组织旨在留住顶尖人才和高价值客户&#xff0c;因此您需要不断为这两个团队提供一流的体验。 就客户而言&#xff0c;它可以实时解决他们的问题和疑虑&#xff0c;并以深思熟虑、可操作的洞察力主动与他们联系&#xff1b;而且&#xff0c;对于员工来说&#xff0c;它可…

如何解决大模型的「幻觉」问题?

如何解决大模型的「幻觉」问题&#xff1f; 如何解决大模型的「幻觉」问题&#xff1f;幻觉产生原因&#xff1f;模型原因数据层面 幻觉怎么评估&#xff1f;Reference-based&#xff08;基于参考信息&#xff09;基于模型的输入、预先定义的目标输出基于模型的输入 Reference-…

实力强大众和策略:股市跌了债市会涨吗?

股市和债市作为两种大规模的证券商场&#xff0c;它们之间有着怎样的关系&#xff0c;比如说&#xff0c;股市跌了债市会涨吗&#xff1f;关于这个问题&#xff0c;本文将凭借有关常识来展开讨论&#xff0c;为大家提供一个参考思路。 股市跌了债市会涨吗&#xff1f; 从理论上…

【Linux】常用的基本命令指令①

前言&#xff1a;从今天开始&#xff0c;我们逐步的学习Linux中的内容&#xff0c;和一些网络的基本概念&#xff0c;各位一起努力呐&#xff01; &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:数据结构 &#x1f448; &#x1f4af;代码…

Go后端开发 -- Go Modules

Go后端开发 – Go Modules 文章目录 Go后端开发 -- Go Modules一、什么是Go Modules?二、GOPATH的工作模式1.GOPATH模式2.GOPATH模式的弊端 三、Go Modules模式创建项目1.go mod命令2.go mod环境变量3.使用Go Modules初始化项目4.修改模块的版本依赖关系 四、Go Modules下impo…