【软考】设计模式之状态模式
目录
- 1. 说明
- 2. 应用场景
- 3. 结构图
- 4. 构成
- 5. 优缺点
- 5.1 优点
- 5.2 缺点
- 6. java示例
- 6.1 非状态模式
- 6.1.1 问题分析
- 6.1.2 接口类
- 6.1.2 实现类
- 6.1.3 客户端
- 6.1.4 结果截图
- 6.2 状态模式
- 6.2.1 抽象状态类
- 6.2.2 状态类
- 6.2.3 上下文类
- 6.2.4 上下文类
1. 说明
- 1.允许一个对象在其内部状态改变时改变它的行为。
- 2.对象看起来似乎修改了它的类。
- 3.对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
2. 应用场景
- 1.一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得开发者可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象独立变化。
3. 结构图

4. 构成
- 1.环境角色:Context(上下文)定义客户端感兴趣的接口;维护一个ConcreteState子类的实例,这个实例定义当前状态
- 2.抽象状态角色:State(状态)定义一个接口以封装与Context的一个特定状态相关的行为
- 3.具体状态角色:ConcreteState(具体状态子类)每个子类实现与Context的一个状态相关的行为
5. 优缺点
5.1 优点
- 1.将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
- 2.允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5.2 缺点
- 1.状态模式的使用必然会增加系统类和对象的个数。
- 2.状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
- 3.状态模式对"开闭原则"的支持并不太好。
6. java示例
6.1 非状态模式
6.1.1 问题分析
- 1.使用了大量的switch case这样的判断(if else也是一样),使程序的可阅读性变差
- 2.扩展性差,如果新加了一种状态,则需要修改判断逻辑
6.1.2 接口类
package com.learning.state.before;/*** 电梯接口*/
public interface ILift {//定义四个电梯状态的常量/*** 打开状态*/int OPENING_STATE = 1;/*** 关闭状态*/int CLOSING_STATE = 2;/*** 运行状态*/int RUNNING_STATE = 3;/*** 停止状态*/int STOPPING_STATE = 4;//设置电梯状态的功能void setState(int state);//电梯操作功能void open();//电梯关闭功能void close();//电梯运行功能void run();//电梯停止功能void stop();
}
6.1.2 实现类
package com.learning.state.before;/*** @Description 电梯类**/
public class Lift implements ILift{//当前电梯状态private int state;@Overridepublic void setState(int state) {this.state = state;}@Overridepublic void open() {switch(state){//如果当前电梯状态是开启状态case OPENING_STATE://什么都不做break;//如果当前电梯状态是关闭状态,打开电梯case CLOSING_STATE:System.out.println("电梯打开了");// 设置当前电梯状态为开启状态setState(OPENING_STATE);break;//如果当前电梯状态是运行状态case RUNNING_STATE://什么都不做break;//如果当前电梯状态是开启状态,打开电梯case STOPPING_STATE:System.out.println("电梯打开了");setState(OPENING_STATE);break;}}@Overridepublic void close() {switch(this.state) {case OPENING_STATE://只有开门状态可以关闭电梯门System.out.println("电梯关门了");//关门之后电梯就是关闭状态了this.setState(CLOSING_STATE);break;case CLOSING_STATE://已经是关门状态,不能关门//什么都不做break;case RUNNING_STATE://运行时电梯门是关着的,不能关门//什么都不做break;case STOPPING_STATE://停止时电梯也是关着的,不能关门//什么都不做break;}}@Overridepublic void run() {switch(this.state) {case OPENING_STATE://电梯不能开着门运行break;case CLOSING_STATE://门关了,可以运行了System.out.println("电梯运行了");//设置为运行状态this.setState(RUNNING_STATE);break;case RUNNING_STATE://已经是运行状态了break;case STOPPING_STATE:System.out.println("电梯运行了");//设置为运行状态this.setState(RUNNING_STATE);break;}}@Overridepublic void stop() {switch(this.state) {case OPENING_STATE:// 开门的电梯已经是是停止的了(正常情况下)break;case CLOSING_STATE:// 关门时才可以停止System.out.println("电梯停止了");this.setState(STOPPING_STATE);break;case RUNNING_STATE:// 运行时当然可以停止了System.out.println("电梯停止了");this.setState(STOPPING_STATE);break;case STOPPING_STATE:break;}}
}
6.1.3 客户端
package com.learning.state.before;/*** 客户端*/
public class Client {public static void main(String[] args) {// 创建电梯对象Lift lift = new Lift();// 设置当前电梯的状态lift.setState(ILift.OPENING_STATE);// 打开lift.open();lift.close();lift.run();lift.stop();}
}
6.1.4 结果截图

6.2 状态模式
6.2.1 抽象状态类
package com.learning.state.after;/*** 抽象状态类*/
public abstract class LiftState {// 声明环境角色类变量protected Context context;public void setContext(Context context){this.context = context;}// 电梯开启操作public abstract void open();// 电梯关闭操作public abstract void close();// 电梯运行操作public abstract void run();// 电梯停止操作public abstract void stop();
}
6.2.2 状态类
- 1.开启状态类
package com.learning.state.after;/*** 开启状态类*/
public class OpeningState extends LiftState {// 当前状态要执行的方法@Overridepublic void open() {System.out.println("电梯开启");}@Overridepublic void close() {// 修改状态super.context.setLiftState(Context.CLOSING_STATE);// 调用当前状态中的context中的close方法super.context.close();}@Overridepublic void run() {// 什么都不做}@Overridepublic void stop() {// 什么都不做}
}
- 2.运行状态类
package com.learning.state.after;/**
* 运行状态类
*/
public class RunningState extends LiftState {/*** 运行的时候是不能开电梯门*/@Overridepublic void open() {// 什么都不做}/*** 运行状态的电梯,门不需要再关*/@Overridepublic void close() {// 什么都不做}/*** 运行状态下要实现的方法*/@Overridepublic void run() {System.out.println("电梯正在运行");}/*** 运行状态可以停止*/@Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}
- 3.停止状态类
package com.learning.state.after;/*** 停止状态类*/
public class StoppingState extends LiftState {/*** 停止状态可以开门*/@Overridepublic void open() {// 状态修改super.context.setLiftState(Context.OPENING_STATE);// 动作委托为CloseState来执行,也就是委托给ClosingState子类执行这个动作super.context.getLiftState().open();}/*** 可以关门,这个动作不归我执行*/@Overridepublic void close() {// 状态修改super.context.setLiftState(Context.CLOSING_STATE);// 动作委托为CloseState来执行,也就是委托给ClosingState子类执行这个动作super.context.getLiftState().close();}/*** 停止后,可以再跑起来*/@Overridepublic void run() {// 状态修改super.context.setLiftState(Context.RUNNING_STATE);// 动作委托为CloseState来执行,也就是委托给ClosingState子类执行这个动作super.context.getLiftState().run();}/*** 停止方法执行*/@Overridepublic void stop() {System.out.println("电梯停止了");}
}
- 4.关闭状态类
package com.learning.state.after;/*** 关闭状态类*/
public class ClosingState extends LiftState {/*** 电梯关闭状态可以再打开*/@Overridepublic void open() {super.context.setLiftState(Context.OPENING_STATE);super.context.open();}/*** 电梯关闭状态实现的动作*/@Overridepublic void close() {System.out.println("电梯门关闭");}/*** 电梯关门之后启动*/@Overridepublic void run() {super.context.setLiftState(Context.RUNNING_STATE);super.context.run();}/*** 电梯门关着,但没按楼层*/@Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}
6.2.3 上下文类
package com.learning.state.after;public class Context {// 定义对应状态对象的常量public final static OpeningState OPENING_STATE = new OpeningState();public final static ClosingState CLOSING_STATE = new ClosingState();public final static RunningState RUNNING_STATE = new RunningState();public final static StoppingState STOPPING_STATE = new StoppingState();// 定义一个当前电梯状态变量private LiftState liftState;public LiftState getLiftState(){return liftState;}public void setLiftState(LiftState liftState){this.liftState = liftState;// 设置当前状态对象中的Context对象this.liftState.setContext(this);}public void open(){this.liftState.open();}public void close(){this.liftState.close();}public void run(){this.liftState.run();}public void stop(){this.liftState.stop();}}
6.2.4 上下文类
package com.learning.state.after;/*** 客户端类*/
public class Client {public static void main(String[] args) {// 创建环境角色对象Context context = new Context();// 设置当前电梯状态context.setLiftState(Context.CLOSING_STATE);context.open();context.close();context.run();context.stop();}
}
相关文章:
【软考】设计模式之状态模式
目录 1. 说明2. 应用场景3. 结构图4. 构成5. 优缺点5.1 优点5.2 缺点 6. java示例6.1 非状态模式6.1.1 问题分析6.1.2 接口类6.1.2 实现类6.1.3 客户端6.1.4 结果截图 6.2 状态模式6.2.1 抽象状态类6.2.2 状态类6.2.3 上下文类6.2.4 上下文类 1. 说明 1.允许一个对象在其内部状…...
MNN介绍、安装与编译:移动端深度学习推理引擎
MNN介绍、安装与编译:移动端深度学习推理引擎 引言第一部分:MNN简介第二部分:MNN的安装第三部分:MNN的编译结语 引言 大家好,这里是程序猿代码之路。在移动设备上实现高效的深度学习模型推理一直是人工智能领域的一个挑…...
A Simple Problem with Integers(线段树)
目录 描述 输入 输出 样例输入 样例输出 思路 建树 第一次错误解法(正确解法在下面,可跳过这一步) 正确解法 code 描述 You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of …...
单元测试(UT)用例简介
单元测试(Unit Testing, UT)用例是一系列预先设计好的、针对软件最小可测试单元的测试场景。每一个单元测试用例都是为了验证一个独立代码单元(如函数、方法、类)的行为是否符合预期。这些用例通常包含以下几个关键组成部分&#…...
Java通过反射机制获取类对象下的属性值
目录 以类USER为例: 使用Java的反射机制获取Column的name为“user_name”的类属性值 以类USER为例: import lombok.Data; import javax.persistence.*; import java.io.Serializable;Data Table(name "user_info") public class User imple…...
IDEA插件开发-File -> New->Project中添加一个myOptions
写一个IDEA插件,在IDEA的File -> New -> Project 中添加一个选项myOptions ,点击myOptions 后弹出一个提示对话框:被点击了 为了在IntelliJ IDEA中创建一个插件,您需要遵循一系列的步骤来开发和集成您的功能。下面是一个简化的指南&am…...
海量数据处理项目-账号微服务和流量包数据库表+索引规范(下)
海量数据处理项目-账号微服务和流量包数据库表索引规范(下) 第2集 账号微服务和流量包数据库表索引规范讲解《下》 简介:账号微服务和流量包数据库表索引规范讲解 账号和流量包的关系:一对多traffic流量包表思考点 海量数据下每…...
Nodejs 16与 gitbook搭建属于你自己的书本网站-第一篇
最近想重新搭建一个网站来存放自己的相关知识点,并向网络公开,有个hexo博客其实也不错的,但是总感觉hexo很多花里胡哨的玩意,导致挂载的博客异常卡,这样反而不利于我自己回顾博客了,于是我就开始钻研这个鬼…...
服务器被CC攻击之后怎么办?
1.取消域名绑定取消域名绑定后Web服务器的CPU能够马上恢复正常状态,通过IP进行访问连接一切正常。但是不足之处也很明显,取消或者更改域名对于别人的访问带来了不变,另外,对于针对IP的CC攻击它是无效的,就算更换域名攻…...
pygame通过重心坐标 用纹理填充三角形
texture_x int(alpha * texture_image.get_width()) texture_y int(beta * texture_image.get_height())为什么没有gama 2024/3/30 15:45:52 在使用重心坐标进行纹理映射时,通常是通过计算 alpha 和 beta 来确定纹理图片上的对应位置,而 gamma 通常是…...
Leetcode 611. 有效三角形的个数
给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。 示例 1: 输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3 示例 2: 输入: nums [4,2,3,4] 输出: 4 提示: 1 < nums.len…...
Openfeign
Openfeign 相关扩展 在 2020 以前的 SpringCloud 采用 Ribbon 作为负载均衡,但是 2020 年之后,SpringCloud 吧 Ribbon 移除了,而是使用自己编写的 LoadBalancer 替代. 因此,如果在没有加入 LoadBalancer 依赖的情况下,…...
五、基于KubeAdm搭建多节点K8S集群
如需查阅上一步骤,请点击下面链接:四、戴尔R630本地服务器Linux Centos7.9系统安装docker-ce-20.10.10-3.el7版本-CSDN博客文章浏览阅读727次,点赞12次,收藏13次。1、准备工作3、Linux Centos7.9系统的iDRAC远程管理、网络设置、SecureCRT远程登录终端、企业级静态ip地址配…...
PC电脑技巧[笔记本通过网线访问设备CMW500]
笔记本局域网访问设备 现在我有一台CMW500,我要用笔记本去访问它,但是我发现没有路由器就是不能够访问,通过网线连接设备就是ping不通: 这里设置TCP/IPv4的IP地址如下,这时候就可以pin通了:...
【接口自动化测试框架】YAML管理接口框架配置的最佳实践
管理接口框架配置是构建强大的接口测试框架的关键一环。良好的配置管理可以提高测试效率、可维护性和可扩展性。在本文中,我们将重点介绍使用YAML(YAML Ain’t Markup Language)来管理接口框架配置的最佳实践,并通过实例演示其用法…...
【进程OI】基本文件操作的系统调用
文章目录 前言open参数flags参数mode writereadclose 前言 当用户想要向磁盘中的文件读写数据,就必须要得到操作系统的允许。同样,操作系统为了能让用户去对文件进行打开、读写、关闭等操作,向上提供了相应的系统调用的接口。C、JAVA、C等语…...
Ubuntu20.04 server系统部署安装(VMware上)和初始化配置
Ubuntu20.04 server部署安装(VMware上)和初始化配置 一、Ubuntu20.04 server系统部署安装上下键控制上下,可以选择配置的目标,回车表示确定,并进行下一步1.1镜像下载2.1 VMware上创建虚拟机2.2 选择语言,键…...
图论最短路径以及floyd算法的MATLAB实现
图论是数学的一个分支,起源于18世纪。1736年,数学家欧拉通过解决“哥尼斯堡七桥问题”,将问题抽象成点和线的关系,并通过理论分析得出结论,这个过程标志着图论的产生,欧拉也因此被称为“图论之父”。图论研…...
微信小程序 - 登录功能实现
一、认证流程 1. 小程序调用wx.login获取登录认证需要的code,并请求开发者服务器。 2. 开发者服务器根据code,appid, appsecret请求微信接口t获取 openid与session_key ,并生成自己的认证token,并返回给小程序。 3.小程序请求开…...
Python连接MySQL
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、整体思路二、连接流程三、表结构及代码实现 一、整体思路 二、连接流程 三、表结构及代码实现 代码块如下: import pymysqlcon pymysql.connect(h…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
