【软考】设计模式之状态模式
目录
- 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…...
水泊梁山108小酒坛之呼保义宋江
宋江【绰号呼保义、及时雨】字公明,是古典名著《水浒传》中的角色。原为山东郓城县押司,他和晁盖互通往来的事被阎婆惜发现,因此怒杀阎婆惜,逃回家隐藏。后前往清风寨投靠花荣,却被清风寨观灯时遭知寨刘高之妻陷害入狱…...
java.lang.ClassNotFoundException: javafx.application.Application
java8(jdk1.8)到java10(jdk10)中内含有JavaFx 在java11(jdk11)以及以后的版本中剥离出来需要开发者独立下载,另行导入download https://gluonhq.com/products/javafx/java --module-path $FX-P…...
腾讯 tendis 替代 redis linux安装使用
下载地址 Tendis存储版 点击下载 linux 解压 tar -zxvf 安装包.tgz cd 解压安装包/scripts 启动 ./start.sh 停止 ./stop.sh 详细配置 修改 /scripts tendisplus.conf # tendisplus configuration for testing # 绑定本机IIP bind 192.168.31.112 port 51002 #设…...
k8s调优--来自gpt
Kubernetes(K8s)性能调优是一个涉及多个方面的过程,旨在提高集群的效率和响应速度。这包括对节点、Pod、服务、网络和存储等多个层面进行调优。下面我将概述一些常见的Kubernetes性能调优方法: 节点级别的调优: 1.资源分配&…...
HTML5+CSS3小实例:旋转中的视差效果
实例:旋转中的视差效果 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scal…...
3-zookeeper之ZAB协议
Zookeeper ZAB协议 概述 ZAB(Zookeeper Automic Broadcast)是一套专门为Zookeeper设计的用于进行原子广播和崩溃恢复的协议ZAB协议主要包含了两个功能 原子广播:保证数据一致性崩溃恢复:保证集群的高可用 ZAB协议本身是基于2PC算法来进行的设计&#…...
如何为企业策划一场XR虚拟直播?
活动年年办,都是老一套,想玩点新花样? 预算有限,但还是想把活动办的逼格高一点? 想通过活动,让更多的人知道自己企业的品牌? 随着AIGC技术的不断演变,企业活动的形式和内容也在不…...
6.3物联网RK3399项目开发实录-驱动开发之I2C 使用(wulianjishu666)
物联网开发源码案例集: 链接:https://pan.baidu.com/s/1kfPDpYZpm_G0GBLAup3KTQ?pwdvgvv I2C 使用 简介 AIO-3399J 开发板上有 9 个片上 I2C 控制器,各个 I2C 的使用情况如下表: 本文主要描述如何在该开发板上配置 I2C。 配置…...
HarmonyOS实战开发-如何构建多种样式弹窗
介绍 本篇Codelab将介绍如何使用弹窗功能,实现四种类型弹窗。分别是:警告弹窗、自定义弹窗、日期滑动选择器弹窗、文本滑动选择器弹窗。需要完成以下功能: 点击左上角返回按钮展示警告弹窗。点击出生日期展示日期滑动选择器弹窗。点击性别展…...
《Effective C++》《构造/析构/赋值运算——7、为多态基类声明virtual析构函数》
文章目录 1、term7:Declare destructors virtual in polymorphic base classes2、总结3、相关面试题3.1 析构函数在什么情况下声明为虚函数 4、参考 1、term7:Declare destructors virtual in polymorphic base classes 带有多态性质的基类应该声明一个virtual析构函数&#x…...
如何做网站的301重定向/新东方雅思培训机构官网
本例介绍《vue.js实战》第五章最后的购物车练习一, 练习1:在当前示例基础上扩展商品列表,新增一项是否选中该商品的功能,总价变为只选中商品的总价,同时提供一个全选按钮 截图如下: html: <div id"app" v-cloak><template v-if"list.length">…...
富通建设有限公司网站/重庆百度推广开户
Javascript 文件操作 一、功能实现核心:FileSystemObject 对象 其实,要在Javascript中实现文件操作功能,主要就是依靠FileSystemobject对象。在详细介绍FileSystemobject对象的各个属性和方法的使用细节前,先来看看这个对象包括哪…...
网站开发难度和小程序开发难度/搜索引擎广告案例
一、Autoit 上传文件、1.常用语法- WinActivate("title") 聚焦到指定活动窗口- ControlFocus ( "title", "窗口文本", controlID) 设置输入焦点到指定窗口的某个控件上;- WinWait ( "title" , "窗口文本&qu…...
党校网站建设栏目内容/怎么做一个网页
本篇文章的主要内容是用PHP实现插入排序,简单却经典的一道算法题,不知你是否记得了,快随小编一起回顾一下吧。插入排序基本思路:将数组分为两个区(已排序区和未排序区),假定数组的第一个元素处于已排序区, …...
南通网站建设方案服务/重庆seo排名优化
1,先到Oracle网站下载Instant Client : http://www.oracle.com/technology/global/cn/software/tech/oci/instantclient/index.html 根据你的操作系统选择不同的Instant Client版本 下载回是一个压缩文件,解压之后的文件夹叫:D:/instantclient_11_2.放在你喜欢的目录即可.例如:…...
网站毕业设计图怎么做/app投放推广
形参为unique_ptr u2,而后实参为std::move(unique_ptr u1),这样会将原本u1的内存传递给u2,避免了传递拷贝。例如: 1 void fun(std::unique_ptr u2) 2 { 3 } 4 5 unique_ptr<cls> u1; 6 fun(std::move(u1));...