深入浅出设计模式 - 状态模式

news2024/12/23 7:12:43

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌

Java知识图谱点击链接:体系化学习Java(Java面试专题)

💕💕 感兴趣的同学可以收藏关注下不然下次找不到哟💕💕

在这里插入图片描述

文章目录

  • 1、什么是状态模式
  • 2、状态模式的优缺点
  • 3、状态模式的应用场景
  • 4、状态模式的结构
  • 5、状态模式的原理
  • 6、状态模式的代码案例

1、什么是状态模式

状态模式是一种行为型设计模式,它允许对象在内部状态改变时改变其行为。在状态模式中,对象的行为取决于其内部状态,而不是取决于外部输入。通过将状态封装成独立的类,并将状态之间的转换逻辑封装在上下文类中,状态模式使得状态的变化更加灵活和可扩展。

在状态模式中,通常会有一个上下文类(Context)和多个具体状态类(Concrete State)。上下文类包含一个当前状态的引用,它会根据当前状态委托相应的行为给具体状态类。当上下文类的状态发生改变时,它会调用具体状态类的方法来实现不同的行为。

2、状态模式的优缺点

状态模式的优点包括:

  1. 将状态的转换逻辑封装在具体状态类中,使得状态变化更加清晰和可维护。

  2. 通过引入新的具体状态类,可以方便地扩展系统的功能。

  3. 遵循开闭原则,对于上下文类而言,可以在不修改其代码的情况下增加新的状态类。

  4. 状态模式将状态的判断逻辑分散到具体状态类中,避免了大量的条件语句,提高了代码的可读性和可维护性。

状态模式的缺点包括:

  1. 引入了多个状态类,增加了系统的复杂性。

  2. 如果状态转换过于复杂,可能会导致状态类之间的相互调用和依赖关系复杂化。

  3. 如果状态转换的逻辑不够清晰,可能会导致状态切换的错误或不完整。

需要根据具体的应用场景来评估是否使用状态模式。在状态变化较为简单且有限的情况下,可能不需要引入状态模式,而在状态变化复杂且需要灵活扩展的情况下,状态模式可以提供一种清晰和可维护的设计方案。

3、状态模式的应用场景

状态模式适用于以下场景:

  1. 对象的行为随着其内部状态的改变而改变,并且需要在运行时动态地改变对象的行为。

  2. 对象具有多个状态,并且在不同状态下有不同的行为。

  3. 有大量的条件语句用于根据对象的状态进行不同的操作,导致代码复杂且难以维护。

  4. 需要在运行时根据对象的状态来决定不同的行为,而不是通过条件语句的方式。

  5. 需要在不修改现有代码的情况下增加新的状态和行为。

  6. 需要将状态转换的逻辑封装在具体状态类中,使得代码更加可读和可维护。

一些常见的应用场景包括:

  1. 订单状态管理:订单可能有不同的状态,如待支付、待发货、已发货等,每个状态对应着不同的行为和操作。

  2. 游戏角色状态:游戏中的角色可能有不同的状态,如正常状态、受伤状态、死亡状态等,每个状态对应着不同的行为和表现。

  3. 线程状态管理:线程可能有不同的状态,如新建状态、运行状态、阻塞状态等,每个状态对应着不同的行为和操作。

  4. 电梯控制系统:电梯可能有不同的状态,如停止状态、运行状态、故障状态等,每个状态对应着不同的行为和操作。

总之,状态模式适用于对象的行为随着其内部状态的改变而改变的情况,可以帮助简化代码、提高可维护性和扩展性。

4、状态模式的结构

状态模式的结构包括以下几个角色:

  1. 环境(Context):环境类是拥有状态的对象,它维护一个对抽象状态类的引用,并在运行时切换状态。环境类将客户端的请求委派给当前状态对象来处理。

  2. 抽象状态(State):抽象状态类定义了一个接口,用于封装与环境类的特定状态相关的行为。它可以是一个抽象类或接口,并且包含了环境类的引用,以便在需要时切换到其他状态。

  3. 具体状态(Concrete State):具体状态类是抽象状态的子类,实现了抽象状态定义的接口。每个具体状态类对应着环境的一个具体状态,负责处理该状态下的行为和操作。

在状态模式中,环境类通过委派给当前状态对象来处理请求,而不是使用条件语句来判断状态并执行相应的操作。这样可以将状态的转换逻辑封装在具体状态类中,使得环境类的代码更加简洁、可读和可维护。

状态模式通过将对象的行为和状态分离,使得对象的行为可以根据其内部状态的改变而改变,同时也方便了新状态的添加和扩展。这种模式可以提高代码的可维护性、可扩展性和可读性。

5、状态模式的原理

状态模式的原理是基于对象的状态来改变对象的行为。它将对象的行为封装成不同的状态类,并将状态的转换逻辑放在环境类中。当对象的状态发生改变时,环境类会委托当前状态对象来处理相应的行为。

状态模式的核心思想是将复杂的条件判断语句转换为对状态对象的委派,从而简化了代码的结构和逻辑。它通过将每个状态封装成独立的类,使得每个状态都可以单独进行扩展和修改,而不会影响其他状态的实现。

在状态模式中,环境类拥有一个对抽象状态类的引用,并在运行时根据需要切换到不同的具体状态对象。环境类将客户端的请求委托给当前状态对象来处理,而具体的行为实现则由具体状态类来完成。

6、状态模式的代码案例

以下是一个简单的状态模式的代码示例,以展示状态模式的实现方式:

package com.pany.camp.design.principle.state;

/**
 *
 * @description: 状态接口
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-28 14:54
 */
public interface State {

    void handle();
}
package com.pany.camp.design.principle.state;

/**
 *
 * @description:  具体状态类A
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-28 14:55
 */
class ConcreteStateA implements State {
    
    @Override
    public void handle() {
        System.out.println("当前状态是A,执行A状态的处理逻辑");
    }
}

package com.pany.camp.design.principle.state;

/**
 *
 * @description: 具体状态类B
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-28 14:56
 */
class ConcreteStateB implements State {
    
    @Override
    public void handle() {
        System.out.println("当前状态是B,执行B状态的处理逻辑");
    }
}

package com.pany.camp.design.principle.state;

/**
 *
 * @description:  环境类
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-28 14:56
 */
class Context {
    private State state;

    public void setState(State state) {
        this.state = state;
    }

    public void request() {
        state.handle();
    }
}
package com.pany.camp.design.principle.state;

/**
 *
 * @description:  客户端类
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-28 14:56
 */
public class Client {

    public static void main(String[] args) {
        Context context = new Context();
        State stateA = new ConcreteStateA();
        State stateB = new ConcreteStateB();

        // 设置初始状态为A
        context.setState(stateA);
        context.request(); // 输出:当前状态是A,执行A状态的处理逻辑

        // 切换状态为B
        context.setState(stateB);
        context.request(); // 输出:当前状态是B,执行B状态的处理逻辑
    }
}

状态接口 State 定义了 handle() 方法,具体的状态类 ConcreteStateA 和 ConcreteStateB 实现了该接口,并分别实现了不同的处理逻辑。环境类 Context 持有一个对当前状态的引用,并在 request() 方法中委托当前状态对象来处理请求。

在测试代码中,首先创建了一个环境类 Context 和两个具体状态类 ConcreteStateA 和 ConcreteStateB 。通过 setState() 方法设置初始状态为A,并调用 request() 方法来执行当前状态的处理逻辑。然后,通过再次调用 setState() 方法切换状态为B,并再次调用 request() 方法来执行B状态的处理逻辑。

输出结果如下:

当前状态是A,执行A状态的处理逻辑
当前状态是B,执行B状态的处理逻辑

Process finished with exit code 0

在这里插入图片描述

💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊
在这里插入图片描述

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

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

相关文章

Day05

目录 1、编写mybatis插件,实现字段自动填充 注意 2、ThreadLocal的简单使用 3、问题:添加员工语句执行成功,但数据库中未添加新员工 4、问题:foreach 1、编写mybatis插件,实现字段自动填充 如何编写插件 Interc…

Jmeter之BeanShell Assertion自定义断言

在JMeter性能测试工具中,BeanShell Assertion是一种强大而灵活的自定义断言方法。 它允许用户通过编写BeanShell脚本来验证服务器返回的响应数据,从而确保系统在各种负载下的稳定性和可靠性。 无论您是初学者还是有经验的专业人士,使用Bean…

Element ui 取消点击空白处弹框关闭的效果

目录 属性: 描述 属性: element组件库的Dialog对话框默认是可以通过点击 modal 关闭 Dialog,即点击空白处弹框可关闭。 描述 在 el-dialog中close-on-click-modal含义是:点击空白处是否关闭,默认true;如…

python实现固定资产梳理的办法

一、需求; 需求:实现xxx地固定资产的计算以及梳理 1.盘点资产,通过excel表格设计了不同的区域,进行每个区域的资产的计数工作,成为了一个登记事项 2.后续形成文本汇报工作,梳理内容 3.需求把表格中同类…

2023金九银十跳槽必会Java核心知识点笔记整理

现在互联网大环境不好,互联网公司纷纷裁员并缩减 HC,更多程序员去竞争更少的就业岗位,整的 IT 行业越来越卷。身为 Java 程序员的我们就更不用说了,上班 8 小时需要做好本职工作,下班后还要不断提升技能、技术栈&#…

沐曦与百度飞桨完成兼容性测试,助力计算机视觉应用发展

近日,沐曦集成电路(上海)有限公司(以下简称“沐曦”)的曦思N100人工智能推理GPU与百度飞桨完成 I 级兼容性测试。测试结果显示,双方兼容性表现良好,整体运行稳定。这是沐曦自2022年9月加入“硬件…

五子棋AI智能算法的测试方法

先前发了几篇五子棋游戏程序设计的博文,设计了游戏程序,也设计了AI智能奕棋的算法,运行程序检测算法的可行性,完成人机模式游戏功能的设置。本文重点介绍测试方法。 对于人机对战的电脑智能应子算法,参阅很多五子棋书…

React项目请求接口跨域设置代理怎么设置

在src 目录下创建setupProxy.js const {createProxyMiddleware} require(http-proxy-middleware)module.exports function(app) {app.use(createProxyMiddleware(/api, { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)target: http://172.20.17.199:808…

学习Kotlin~函数

有名函数 函数参数 不打算传入值参,可以预先给参数指定默认值 //如果不打算传入值参,可以预先给参数指定默认值private fun fix(name: String, age: Int 2) {println(name age);}//调用的时候fix("hhhh");fix("hasee", 30);有名的…

【Html】Html+Less实现一个简单的加载动画

效果 运行环境 系统&#xff1a;Win10系统 IDE&#xff1a;Visual Studio Code v1.79.2 VSCode插件&#xff1a;Easy LESS v2.0.0 index.html代码 <!DOCTYPE html> <html><head><title>加载动画</title><link rel"stylesheet" hr…

Android的Context详解 - 揭开Context的神秘面纱

这篇文章是基于我四年前的一篇文章进行更正和深入探究。背景是&#xff0c;2019年4月份我在找工作&#xff0c;看到一个问题&#xff0c;问this&#xff0c;getBaseContext()、getApplication()、getApplicationContext()的区别。当时我写了简单的demo验证&#xff0c;得出了跟…

看看螯合物前体多肽试剂DOTA-E[c(RGDfK)2]的全面解析吧!

【产品描述】 DOTA-E[c(RGDfK)2]螯合物前体多肽试剂&#xff0c;RGD肽指含有Arg-Gly-Asp三个氨基酸组成的序列多肽&#xff0c;可以提供大量的RGD直线肽&#xff0c;RGD环肽&#xff0c;RGD双环肽、RGD模拟肽等&#xff0c;也可以根据客户需求定制RGD肽。 DOTA-E [c (RGDfK) 2…

6.3 B树

多路平衡查找树 1.定义 B树的阶&#xff1a;B树中所有结点的孩子个数的最大值&#xff0c;表示成m m阶B树&#xff1a;空树或者满足如下特性的m叉树 特性&#xff1a; 1.树中每个结点最多子树 m 关键字m-1 2.根节点不是终端结点&#xff0c;至少有两棵子树 3.根结点除外&…

Java 遍历List的两种方式

可参考文章 Notepad编译并运行java代码_notepad怎么运行java代码_西晋的no1的博客-CSDN博客 中的第二种方法测试下述代码。 在java中&#xff0c;可以使用for循环和使用for-each循环两种方式遍历List。 1.使用for循环遍历List 2.使用for-each遍历List 注意&#xff1a;使用for-…

Java使用Maven工程操作OpenGL ES绘制三角形和圆形;绘制完成后操作键盘控制然图形移动

OpenGL ES 绘制三角形&#xff0c;操作键盘移动位置 PS&#xff1a;想快速看到效果的小伙伴&#xff0c;可以在引入依赖后&#xff0c;先跳到完整代码部分 第一步&#xff1a;依赖引入 <properties><lwjgl.version>3.2.3</lwjgl.version><joml.version&…

mysql 密码丢失的解决方案

问题描述 mysql 密码丢失的解决方案 解决方案&#xff1a; 停止服务; 重新启动服务&#xff1a;mysqld.exe --skip-grant-tables //启动服务器但是跳过权限; 当前启动的服务器没有权限概念&#xff1a;非常危险&#xff0c;任何客户端&#xff0c;不需要任何用户信息都可…

Pycharm连接远端Python环境操作Spark

文章目录 1. 创建工程&#xff0c;指定远端python解析器2. 添加远端python解析器3.配置完成4.本地文件自动同步远端5.删除远端python解析器(非必须操作&#xff0c;重新配置时参考该项)6. 文件模板配置 远程连接方案, 允许程序员连接远端测试环境, 确保环境的统一, 避免各种环境…

消息队列中间件(一)

场景 流量削峰 应用解耦 异步处理 分类 ActiveMQ 优&#xff1a;单机吞吐万级&#xff0c;时效性ms级&#xff0c;可用性高&#xff08;主从架构&#xff09;&#xff0c;可靠性高&#xff08;丢失率低&#xff09; 缺&#xff1a;官方维护少&#xff0c;高吞吐场景较少…

QT Creator上位机学习(二)基础控件及信号与槽

c# 系列文章目录 文章目录 布局控件信号与槽程序图标使用技巧 布局控件 美化界面的时候&#xff0c;经常需要进行一些控件的布局&#xff0c;这时需要使用一些容器类。 在快捷栏出&#xff0c;也有一些布局设计的选择 如上图&#xff0c;其中涉及到几种编辑状态&#xff1…

Math简单学习

1.绝对值 就变个符号 public static double abs(double a) {return (a < 0.0D) ? 0.0D - a : a; }public static float abs(float a) {return (a < 0.0F) ? 0.0F - a : a;}public static int abs(int a) {return (a < 0) ? -a : a;}IntrinsicCandidatepublic sta…