GPT带我学-设计模式12-状态模式

啥是状态模式

状态模式是一种行为型设计模式,它允许一个对象在其内部状态发生改变时改变其行为。状态模式将对象的状态封装成不同的类,并使得对象在运行时可以动态地改变状态,从而改变对象的行为。状态模式的主要目的是促进代码的复用和灵活性。

状态模式中包含以下几个角色:

  1. 上下文(Context):上下文是包含了多个状态的对象,它提供了一个接口用于客户端访问状态。

  2. 抽象状态(State):抽象状态是所有具体状态的父类或接口,它定义了所有具体状态所需实现的方法。

  3. 具体状态(Concrete State):具体状态是继承自抽象状态的子类,它实现了抽象状态所定义的方法并且根据自身状态来处理上下文的请求。

当一个对象的内部状态发生变化时,该对象会将请求委托给与当前状态相应的具体状态进行处理。这样,对象的行为就会随着状态的改变而改变,从而避免了大量的if-else语句。状态模式还可以通过添加新的具体状态类来扩展一个系统,并且符合开闭原则。

常见的应用场景

状态模式的应用场景通常包括以下几个方面:

  1. 对象的行为随着内部状态的改变而改变。例如,在开发一个订单系统时,订单的状态可能包括已生成、已支付、已发货、已完成等不同的状态,针对不同的状态,订单对象会执行不同的操作。

  2. 代码中包含大量的条件语句。例如,当需要判断用户的登录状态(已登录或未登录)时,往往需要使用大量的if-else语句来处理,而使用状态模式可以将这些条件语句转化为不同的状态类,从而增强了代码的可维护性和可扩展性。

  3. 需要在运行时根据一个对象的状态来改变其行为。例如,在一款游戏中,角色的状态可能包括生命值、魔法值等属性,当某个属性值发生变化时,角色的行为也会相应地改变。

  4. 对象的状态转换次数比较频繁。例如,在一个电商平台上,商品的状态可能会经常发生变化,从“待审核”到“审核通过”再到“已上架”等多个状态之间进行切换,此时使用状态模式可以优雅地处理这种状态转换过程。

综上所述,状态模式是一种非常实用的设计模式,可以使得对象的行为更具灵活性和易维护性,适合处理复杂的对象状态转换问题。

例子1

假设有一个用户管理系统,需要判断当前用户是否已经登录。

使用状态模式

通过不同状态去执行不同逻辑。
首先定义一个状态接口LoginState,并在接口中定义了两个方法:

public interface LoginState {void handle();String getStateName();
}

其中handle()方法表示处理该状态的方法,getStateName()方法返回该状态的名称。然后定义两个具体状态类:LoggedInState和LoggedOutState。

public class LoggedInState implements LoginState {@Overridepublic void handle() {System.out.println("当前用户已登录");}@Overridepublic String getStateName() {return "已登录";}
}public class LoggedOutState implements LoginState {@Overridepublic void handle() {System.out.println("当前用户未登录");}@Overridepublic String getStateName() {return "未登录";}
}

接下来定义一个用户类User,用于保存当前用户的状态,并提供一个方法getUserState()用于获取当前用户的状态。

public class User {private LoginState state;public User(LoginState state) {this.state = state;}public void setState(LoginState state) {this.state = state;}public LoginState getUserState() {return state;}
}

最后,在客户端代码中,可以根据当前用户的状态来执行不同的操作:

public static void main(String[] args) {User user = new User(new LoggedOutState()); // 初始状态为未登录// 根据当前用户状态执行不同的操作user.getUserState().handle();
}

运行上述代码,输出结果如下:

当前用户未登录

如果将User对象的状态改为已登录,再次运行代码,输出结果如下:

当前用户已登录

通过使用状态模式,我们可以将原本大量的if-else语句转换成不同的状态类,从而使得代码更加清晰易懂、易维护。

不使用状态模式

如果不使用状态模式,我们可能会在代码中使用很多的if-else语句来判断当前用户的状态。例如,在用户管理系统中,可能会有很多个地方需要根据当前用户是否已登录来执行不同的逻辑,这时候就会写出很多类似下面这样的代码:

User user = getCurrentUser();
if (user != null && user.isLoggedIn()) {// 执行已登录用户的操作
} else {// 执行未登录用户的操作
}

这样的代码虽然简单,但是如果在多处都要进行状态判断,就会导致代码冗余度很高、可读性差、扩展性也不好。

而使用状态模式,我们可以将状态的处理逻辑封装到不同的状态类中,从而避免了大量的if-else语句。此外,状态模式还可以让我们添加新的状态变得更加容易,只需要添加一个新的具体状态类即可。因此,使用状态模式来处理对象的状态会使我们的代码更加清晰、灵活、易于维护和扩展。

例子2

需要在运行时根据一个对象的状态来改变其行为。例如,在一款游戏中,角色的状态可能包括生命值、魔法值等属性,当某个属性值发生变化时,角色的行为也会相应地改变。

假设有一个名为Character的类表示游戏中的角色。该类包含以下属性:

  • healthPoints:角色的生命值
  • magicPoints:角色的魔法值
  • currentState:角色当前的状态(存活、昏迷、死亡等)

当角色的生命值或魔法值发生变化时,角色的状态也会随之发生改变,从而影响角色的行为。
首先,我们需要定义状态接口和具体状态类:

// 状态接口
public interface CharacterState {void handle();
}// 具体状态类 - 存活状态
public class AliveState implements CharacterState {private Character character;public AliveState(Character character) {this.character = character;}@Overridepublic void handle() {// 在存活状态下,角色可以执行各种行为System.out.println("角色处于存活状态,可以执行各种行为");}
}// 具体状态类 - 昏迷状态
public class UnconsciousState implements CharacterState {private Character character;public UnconsciousState(Character character) {this.character = character;}@Overridepublic void handle() {// 在昏迷状态下,角色无法执行任何行为System.out.println("角色处于昏迷状态,无法执行任何行为");}
}// 具体状态类 - 死亡状态
public class DeadState implements CharacterState {private Character character;public DeadState(Character character) {this.character = character;}@Overridepublic void handle() {// 在死亡状态下,角色无法执行任何行为System.out.println("角色已死亡,无法执行任何行为");// 当生命值超过0时,进入昏迷状态if (character.getHealthPoints() > 0) {character.changeState(new UnconsciousState(character));}}
}

然后,我们需要定义Character类,并在其中保存当前状态,并提供相应的操作方法来改变角色状态:

public class Character {// 角色属性private int healthPoints;   // 生命值private int magicPoints;    // 魔法值// 角色状态private CharacterState state;public Character(int healthPoints, int magicPoints) {this.healthPoints = healthPoints;this.magicPoints = magicPoints;this.state = new AliveState(this);}// 改变角色状态public void changeState(CharacterState newState) {this.state = newState;}// 获取当前角色状态public CharacterState getCurrentState() {return this.state;}// 角色受到伤害public void takeDamage(int damage) {healthPoints -= damage;if (healthPoints <= 0) {// 如果生命值小于等于0,则进入死亡状态changeState(new DeadState(this));} else if (healthPoints < 10) {// 如果生命值低于一定值,则进入昏迷状态changeState(new UnconsciousState(this));}}// 角色恢复生命值public void restoreHealth(int amount) {healthPoints += amount;if (state instanceof UnconsciousState && healthPoints >= 10) {// 如果之前处于昏迷状态,但现在生命值超过一定值,则恢复为存活状态changeState(new AliveState(this));}}// 角色消耗魔法值public void consumeMagic(int amount) {magicPoints -= amount;if (magicPoints < 0) {// 如果魔法值小于0,则进入昏迷状态changeState(new UnconsciousState(this));}}// 角色恢复魔法值public void restoreMagic(int amount) {magicPoints += amount;if (state instanceof UnconsciousState && magicPoints >= 10) {// 如果之前处于昏迷状态,但现在魔法值超过一定值,则恢复为存活状态changeState(new AliveState(this));}}
}

最后,我们可以创建一个Character对象并测试其行为变化:

public class Main {public static void main(String[] args) {// 20点生命值,10点魔法值Character character = new Character(20, 10);character.getCurrentState().handle(); // 输出:角色处于存活状态,可以执行各种行为character.takeDamage(25); // 角色受到25点伤害,进入死亡状态character.getCurrentState().handle(); // 输出:角色已死亡,无法执行任何行为character.restoreHealth(10); // 角色恢复10点生命值,但无法改变状态character.getCurrentState().handle(); // 输出:角色已死亡,无法执行任何行为character.restoreMagic(20); // 角色恢复20点魔法值,从死亡状态进入昏迷状态character.getCurrentState().handle(); // 输出:角色处于昏迷状态,无法执行任何行为character.consumeMagic(5); // 角色消耗5点魔法值,仍然处于昏迷状态character.getCurrentState().handle(); // 输出:角色处于昏迷状态,无法执行任何行为character.restoreHealth(15); // 角色恢复15点生命值,从昏迷状态进入存活状态character.getCurrentState().handle(); // 输出:角色处于存活状态,可以执行各种行为}
}

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

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

相关文章

Terraform资源地址

在编码时有时会需要引用一些资源的输出属性或是一些模块的输出值&#xff0c;这都涉及到如何在代码中引用特定模块或是资源。另外在执行某些命令行操作时也需要显式指定一些目标资源&#xff0c;这时要掌握Terraform的资源路径规则。 一个资源地址是用以在一个庞大的基础设施中…

Python_4-远程连接Linux

文章目录 使用Python通过SSH自动化Linux主机管理代码执行ls结果&#xff1a;文件传输&#xff1a; 使用Python通过SSH自动化Linux主机管理 在系统管理与自动化运维中&#xff0c;SSH&#xff08;Secure Shell&#xff09;是一个常用的协议&#xff0c;用于安全地访问远程计算机…

FTP协议与工作原理

一、FTP协议 FTP&#xff08;FileTransferProtocol&#xff09;文件传输协议&#xff1a;用于Internet上的控制文件的双向传输&#xff0c;是一个应用程序&#xff08;Application&#xff09;。基于不同的操作系统有不同的FTP应用程序&#xff0c;而所有这些应用程序都遵守同…

富格林:累积经验阻挠黑幕之手

富格林认为&#xff0c;近年来现货黄金投资市场越发火热&#xff0c;许多投资新手纷纷涌入现货黄金市场中。不过&#xff0c;在这需要提醒大家的是要提防黑幕阻挠我们顺利盈利&#xff0c;选择正规可靠的平台进行开户&#xff0c;这样可以保证投资环境的安全稳定。下面富格林将…

水泥分类和使用方式 宁波水泥菱湖新阳水泥厂325鄞州东钱湖春晓咸祥海螺425水泥镇海骆驼庄市

水泥分类和使用方式 宁波水泥菱湖新阳水泥厂325鄞州东钱湖春晓咸祥海螺425水泥镇海骆驼庄市 水泥是一种重要的建筑材料&#xff0c;广泛应用于建筑、桥梁、隧道等各种土木工程项目中。根据不同的分类标准&#xff0c;水泥可以分为多种类型&#xff0c;每种类型的水泥都有其特定…

怎么给word文件名批量替换部分文字?word设置批量替换文字教程

批量替换Word文件名中的几个字&#xff0c;对于经常处理大量文件的人来说&#xff0c;是一项非常实用的技能。以下是一个详细的步骤指南&#xff0c;帮助你快速完成这项任务。 首先&#xff0c;你需要准备一个可以批量重命名文件的工具。市面上有很多这样的工具可供选择&#x…

win10禁止自动更新的终极方法

添加注册表值 1.运行&#xff0c;输入regedit 2.打开注册表编辑器依次进入以下路径“计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings”。 3.在Settings项中&#xff0c;新建DWORD&#xff08;32位&#xff09;值(D)&#xff0c;重命名为以下命名“Fl…

easy_ssti_ctfshow_2023愚人杯

https://ctf.show/challenges#easy_ssti-3969 2023愚人杯有提示app.zip&#xff0c;访问 https://1f660587-5340-4b20-b929-c4549d9a5d4b.challenge.ctf.show/app.zip得到压缩包&#xff0c;拿到一个py文件 可以看到参数名是name&#xff0c;对参数进行筛选&#xff0c;包含ge…

人力资源管理新视野:挖掘员工潜力,共筑卓越未来

在21世纪的商业环境中&#xff0c;企业的成功不再仅仅依赖于资本、技术和市场策略&#xff0c;而更多地依赖于其人力资源的有效管理。人力资源管理的新视野正致力于挖掘员工的潜力&#xff0c;为企业创造持续的价值&#xff0c;共筑卓越的未来。 一、员工潜力的挖掘 员工是企业…

Linux如何查看JDK的安装路径

方法1 echo $JAVA_HOME 如果配置了系统就会输出配置为JAVA_HOME的jdk的的位置&#xff0c;如果没有配置就没有输出&#xff0c;推荐使用方法2 方法2(推荐) 关键命令分别为 1. which java 2. ls -lrt /usr/bin/java &#xff08;路径依照自己的输出灵活去改&…

《Fundamentals of Power Electronics》——脉宽调制器建模

下图给出了一个简单脉宽调制器电路的原理图。 脉宽调制器电路产生一个用于指令转换器功率管导通和关断的逻辑信号δ(t)。该逻辑信号δ(t)是周期性的&#xff0c;其频率为fs&#xff0c;占空比为d(t)。脉宽调制器的输入是一个模拟控制信号vc(t)。脉宽调制器的作用是产生一个与模…

Qt QShortcut快捷键类详解

1.简介 QShortcut是一个方便的工具类&#xff0c;用于在应用程序中创建快捷键。通过设置快捷键和关联的处理函数&#xff0c;可以实现快速执行某个操作的功能。 // 创建一个快捷键&#xff0c;关联到MyWidget类的keyPressEvent()函数 QShortcut *shortcut new QShortcut(QKe…

生产管理驾驶舱模板分享,制造业都来抄作业!

今天要讲的是一张从组织、生产车间、物料、仓库、时间等不同维度&#xff0c;展示产能、产量、投入成本、产能达成率等关键信息&#xff0c;让企业运营决策者全面了解生产产能情况、产量情况、投入成本情况、产能达成率情况的BI生产管理驾驶舱模板。这是奥威BI标准方案为设有生…

问题管理员的工作角色、职责和技能

问题管理就是识别、分析和解决反复出现的根本原因问题并永久修复它们。听起来很简单对吧&#xff0c;不幸的是&#xff0c;情况并非总是如此。对于组织来说&#xff0c;IT问题管理一直是一门棘手的 ITSM 学科。一个经常被忽视的关键因素是有效的问题 管理不仅仅是工具和流程。 …

Yarn的安装和使用详细教程(Mac/Window)

目录 Yarn是什么&#xff1f; Mac安装Yarn 使用Homebrew安装Yarn 使用npm安装Yarn Windows安装Yarn 使用npm安装Yarn Yarn使用 常用命令&#xff1a; 特殊命令&#xff1a; Yarn是什么&#xff1f; Yarn是一个流行的包管理工具&#xff0c;用于管理JavaScript项目的依…

Linux的打包压缩

为什么要打包压缩 文件传输: 在网络上传输多个文件时&#xff0c;可能会因为文件的数量和大小造成传输效率低下。打包可以将多个文件合并为一个文件进行传输&#xff0c;减少网络连接的次数&#xff0c;避免网络传输的开销。压缩文件的体积更小&#xff0c;可以减少网络带宽的消…

Swagger使用和注释介绍

一&#xff1a;介绍 1、什么是Swagger Swagger是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法&#xff0c;参数和模型紧密集成到服务器端的代码&#xff…

karateclub,一个超酷的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超酷的 Python 库 - karateclub。 Github地址&#xff1a;https://github.com/benedekrozemberczki/karateclub Python karateclub是一个用于图嵌入和图聚类的库&#xff…

Springboot+mybatis升级版(Postman测试)

一、项目结构 1.导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apach…

ollama 运行第三方模型

ollama 运行第三方模型 Ollama 默认直接支持很多模型,只需要简单的使用 ollama run命令,示例如下: ollama run gemma:2b就可安装、启动、使用对应模型,这个命令在模型不存在的时候会自动查找并且下载模型,然后运行模型,官方支持的模型我们可以通过https://ollama.com/l…