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 {
    @Override
    public void handle() {
        System.out.println("当前用户已登录");
    }

    @Override
    public String getStateName() {
        return "已登录";
    }
}

public class LoggedOutState implements LoginState {
    @Override
    public void handle() {
        System.out.println("当前用户未登录");
    }

    @Override
    public 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;
    }

    @Override
    public void handle() {
        // 在存活状态下,角色可以执行各种行为
        System.out.println("角色处于存活状态,可以执行各种行为");
    }
}

// 具体状态类 - 昏迷状态
public class UnconsciousState implements CharacterState {
    private Character character;

    public UnconsciousState(Character character) {
        this.character = character;
    }

    @Override
    public void handle() {
        // 在昏迷状态下,角色无法执行任何行为
        System.out.println("角色处于昏迷状态,无法执行任何行为");
    }
}

// 具体状态类 - 死亡状态
public class DeadState implements CharacterState {
    private Character character;

    public DeadState(Character character) {
        this.character = character;
    }

    @Override
    public 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.mfbz.cn/a/597205.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于FPGA的数字信号处理(9)--定点数据的两种溢出处理模式:饱和(Saturate)和绕回(Wrap)

1、前言 在逻辑设计中&#xff0c;为了保证运算结果的正确性&#xff0c;常常需要对结果的位宽进行扩展。比如2个3bits的无符号数相加&#xff0c;只有将结果设定为4bits&#xff0c;才能保证结果一定是正确的。不然&#xff0c;某些情况如77 14(1110)&#xff0c;如果结果只…

部署YUM仓库以及NFS共享服务

YUM仓库部署 一.YUM概述 YUM仓库源是一种软件包管理工具&#xff0c;用于在Linux系统上安装、更新和删除软件包。YUM仓库源包含了软件包的元数据信息和实际的软件包文件。用户可以通过配置YUM仓库源&#xff0c;从中下载和安装软件包。 常见的YUM仓库源包括&#xff1a; 本…

【一起深度吧!】24/05/03

池化层 最大池化和平均层化&#xff1a;最大池化&#xff1a;平均池化&#xff1a; 从零实现池化层&#xff1a; 最大池化和平均层化&#xff1a; 池化的作用: 1、可以降维&#xff0c;减少要 训练的参数。 2、提取特征&#xff0c;也就是保留主要的特征&#xff0c;过滤掉不重…

7-zip下载、安装

7-Zip 官方中文网站 (sparanoid.com) 7-Zip - 程序下载 (sparanoid.com)

Unity 性能优化之图片优化(八)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、可以提前和美术商量的事1.避免内存浪费&#xff08;UI图片&#xff0c;不是贴图&#xff09;2.提升图片性能 二、图片优化1.图片Max Size修改&#x…

Eayswoole 报错 crontab info is abnormal

在执行一个指定的定时任务时 如 php easyswoole crontab show 报错 crontab info is abnormal 如下图所示&#xff1a; 查询了半天 修改了如下配置&#xff1a; 旧的 // 创建定时任务实例 $crontab new \EasySwoole\Crontab\Crontab($crontabConfig); 修改后&#…

山海鲸医疗科技:引领智慧医疗新潮流

随着科技的飞速发展&#xff0c;智慧医疗已经成为医疗行业创新的重要方向。在这个背景下&#xff0c;山海鲸智慧医疗解决方案应运而生&#xff0c;以其先进的技术和全面的服务&#xff0c;为医疗行业带来了前所未有的变革。 山海鲸智慧医疗解决方案是一套集成医疗信息化、大数…

【OneAPI】网页截图API

OneAPI新接口发布&#xff1a;网页截图 可生成指定URL的网页截图。 接口地址&#xff1a;https://oneapi.coderbox.cn/openapi/api/webpage/screenshot 请求参数 参数名类型必填含义说明urlstring是要截图的网页链接例如&#xff1a;https://baidu.comwidthnumber否截图宽度…

龙迅LT9211D MIPI桥接到2 PORT LVDS,分辨率支持高达3840*2160*30HZ

龙迅LT9211D描述&#xff1a; Lontium LT9211D是一款高性能的MIPI DSI/CSI- 2到双端口LVDS转换器。LT9211D反序列化输入的MIPI视频数据&#xff0c;解码数据包&#xff0c;并将格式化的视频数据流转换为AP和移动显示面板或摄像机之间的LVDS发射机输出。LT9211D支持最大14 dB输…

手机运营商二要素验证接口:确保业务操作安全可靠

手机运营商二要素验证接口是一种通过与电信运营商合作的方式&#xff0c;检验手机用户的手机号码与姓名是否一致的服务。这个接口可以广泛应用于各种需要用户实名认证的场景&#xff0c;例如电商、游戏、直播以及金融等行业。 这个接口的作用非常重要&#xff0c;它可以帮助企…

C++——list的特性及使用

list的特性 STL中的list是指带头双向循环列表&#xff0c;list每个元素的存储相互独立&#xff0c;因为其节点存储位置独立不连续&#xff0c;其插入和删除不需要挪动其他元素效率比起vector更高。但也因为存储空间不连续的问题&#xff0c;不能做到和vector一样的随机…

鸿蒙编译子系统详解(二)main.py

1.5.4源码解析 1.5.4.1 build/hb/main.py脚本 这个脚本是编译的主程序脚本&#xff0c;流程如下&#xff1a; 首先是初始化各种module类&#xff0c;然后运行对应模块。 hb分为build,set,env,clean,tool,help几个模块&#xff0c;模块源码位于build/hb/modules/目录下&#xff…

学生管理系统初级

根据题目要求生成大纲 总结: 1.在书写时&#xff0c;考虑到了书写时id可是是abc... 类型是String&#xff0c;但在根据id获取集合中元素时 list.get() &#xff0c;get&#xff08;&#xff09;里面是int类型。 2.在书写还有一点功能并不完全&#xff0c; 2.1查找时是打印所有…

【NodeMCU实时天气时钟温湿度项目 1】连接点亮SPI-TFT屏幕和UI布局设计

前言 从今天开始&#xff0c;我们详解介绍制作实时天气时钟项目的方法步骤&#xff0c;主要分以下几个专题分别进行&#xff1a;&#xff08;1&#xff09;连接点亮SPI-TFT屏幕和UI布局设计&#xff1b;&#xff08;2&#xff09;NodeMCU的WIFI模式设置及连接&#xff1b;&…

车牌号识别系统:PyQT5+QT Designe+crnn/PaddleOCR+YOLO+OpenCV矫正算法。

PyQT5&QT Designecrnn/PaddleOCRYOLO传统OpenCV矫正算法。可视化的车牌识别系统项目。 车牌号识别系统 项目绪论1.项目展示2.视频展示3.整体思路 一、PyQT5 和 QT Designer1.简介2.安装3.使用 二、YOLO检测算法三、OpenCV矫正算法四、crnn/PaddleOCR字符识别算法五、QT界面…

FreeRTOS任务详解

一、任务的创建与删除 1.任务的基本概念 RTOS系统的核心就是任务管理,FreeRTOS 也不例外,而且大多数学习 RTOS 系统的工程 师或者学生主要就是为了使用 RTOS 的多任务处理功能,初步上手 RTOS 系统首先必须掌握的 也是任务的创建、删除、挂起和恢复等操作,由此可见任务管理…

限量背包问题

问题描述 限量背包问题&#xff1a;从m个物品中挑选出最多v个物品放入容量为n的背包。 问题分析 限量背包问题&#xff0c;可以用来解决许多问题&#xff0c;例如要求从n个物品中挑选出最多v个物品放入容量为m的背包使得背包最后的价值最大&#xff0c;或者总共有多少种放法…

我独自升级:崛起怎么下载 我独自升级游戏下载教程分享

定于5月8日全球揭幕的《我独自升级崛起》——一款扣人心弦的动作RPG巨制&#xff0c;灵感采撷于同名动画及网络漫画的热潮&#xff0c;誓将引领满怀热忱的玩家步入一场交织着深邃探索和宏大规模的奇妙冒险。该游戏立足于一个独树一帜的网络武侠宇宙&#xff0c;细腻刻画了一个凡…

VSCode通过SSH连接虚拟机Ubuntu失败

问题说明 最近使用VSCode通过SSH连接Ubuntu&#xff0c;通过VSCode访问Ubuntu进行项目开发&#xff0c;发现连接失败 在VSCode中进行SSH配置 这些都没有问题&#xff0c;但在进行连接时候出现了问题&#xff0c;如下&#xff1a; 出现了下面这个弹窗 解决方法 发现当…

软件测试职责

软件测试职责主要包括以下几个方面&#xff1a; 1. 需求分析&#xff1a;理解软件需求规格说明书&#xff0c;确保测试活动覆盖所有的功能需求和非功能需求&#xff08;如性能、安全性、兼容性等&#xff09;。 2. 测试计划制定&#xff1a;根据项目需求&#xff0c;设计测试…
最新文章