设计模式(十五)状态模式
请直接看原文:
设计模式系列
-------------------------------------------------------------------------------------------------------------------------------
前言
建议在阅读本文前先阅读设计模式(十一)策略模式这篇文章,虽说状态模式和策略模式的结构几乎是相同的,但是它们所解决的问题是不同的,读完这两篇文章你就会有了答案。
1.状态模式定义
状态模式定义
定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式UML图

在享元模式中有如下角色:
- Context:环境角色,定义客户端需要的接口,并且负责具体状态的切换。
- State:抽象状态角色,可以是抽象类或者接口,负责对象状态定义,并封装了环境角色。
- ConcreteState:具体状态角色,实现抽象角色类,定义了本状态所要做的事情。
2.简单实现状态模式
拿用mp3听歌来说,mp3有四种基本状态,分别是开机、关机、上一首歌和下一首歌。如果我们要写一个对mp3进行控制的类,你可能会这样写,如下所示。
public class Mp3Controller {private static final int POWER_ON = 1;private static final int POWER_OFF = 2;private int state = POWER_OFF;public void powerOn() {if (state == POWER_OFF) {System.out.println("开机");}state = POWER_ON;}public void powerOff() {if (state == POWER_ON) {System.out.println("关机");}state = POWER_OFF;}public void preSong() {if (state == POWER_ON) {System.out.println("上一首歌");}}public void nextSong() {if (state == POWER_ON) {System.out.println("下一首歌");}}
}
在powerOn和powerOff方法中我们会将state置为相应的状态,在preSong和nextSong方法中,首先要判断当前mp3的state,如果是POWER_OFF,则不做任何处理,写到这里你可能会觉得实现很简单啊。那么我再添加些状态,比如待机状态、休眠状态、亮屏状态等等,顺便再添加些功能,比如调大音量、调小音量、降噪等。这样你实现起来,就会发现你会定义很多种状态,在功能中可能要用到多个条件语句进行判断,这会使得代码变得臃肿。
状态模式就是为了解决这一问题,将多个条件语句去掉,使得代码更加清晰,下面来进行实现。
抽象状态角色
public interface Mp3State {//开机public void powerOn();//关机public void powerOff();//上一首歌曲public void preSong();//下一首歌曲public void nextSong();
}
接口Mp3State中定义了四种功能,接下来我们来实现Mp3State。
具体状态角色
我们先来实现开机状态,代码如下所示。
public class PowerOnState implements Mp3State {@Overridepublic void powerOn() {System.out.println("已开机");}@Overridepublic void powerOff() {System.out.println("关机");}@Overridepublic void preSong() {System.out.println("上一首歌");}@Overridepublic void nextSong() {System.out.println("下一首歌");}
}
比较特殊的是powerOn方法中,打印了“已开机”,因为在PowerOnState 状态下进行开机操作是多此一举的。
接着实现关机状态:
public class PowerOffState implements Mp3State {@Overridepublic void powerOn() {System.out.println("开机");}@Overridepublic void powerOff() {}@Overridepublic void preSong() {}@Overridepublic void nextSong() {}
}
在关机状态中只实现了powerOn方法,其他的方法都是空实现。
环境角色
public class Context {private Mp3State mp3State;public void setMp3State(Mp3State mp3State){this.mp3State=mp3State;}public void powerOn(){mp3State.powerOn();setMp3State(new PowerOnState());}public void powerOff(){mp3State.powerOff();setMp3State(new PowerOffState());}public void preSong(){mp3State.preSong();}public void nextSong(){mp3State.nextSong();}
}
Context 中定义了setMp3State方法,用来设定状态,其中powerOn方法中会调用setMp3State方法将状态置为PowerOffState,同理powerOff中将状态置为PowerOffState。
客户端调用
public class Client {public static void main(String[] args){Context context=new Context();context.setMp3State(new PowerOffState());context.preSong();context.powerOn();context.nextSong();context.powerOff();}
}
我们只需要先设定mp3的初始状态,就可以调用各种功能方法了,不需要再考虑功能和状态之间的关系。输出结果为:
开机
下一首歌
关机
虽然这个例子的代码很简单,这里还是给出UML图,如下所示。

3.状态模式的使用场景和优缺点
优点
- 避免了过多的条件语句,使得结构更清晰,提高代码的可维护性。
- 每个状态都是一个子类,方便增加和修改状态。
- 状态被放置到类的内部,外部调用不需要知道类的内部如何实现状态和行为的变换。
缺点
- 完全使用状态模式,可能会导致子类会过多。
使用场景
- 代码中包含大量与对象状态有关的条件语句。
- 对象的行为依赖着状态,并且行为随着状态的改变而改变。
相关文章:
设计模式(十五)状态模式
请直接看原文:设计模式系列 ------------------------------------------------------------------------------------------------------------------------------- 前言 建议在阅读本文前先阅读设计模式(十一)策略模式这篇文章,虽说状态…...
Java基于SpringBoot的在线文档管理系统的设计与实现论文
摘 要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,在线文档管理当然也不能排除在外。在线文档管理系统是以实际运用为开发背景,运用软件工程原理和开发方法&am…...
突破编程_C++_STL教程( list 的高级特性)
1 std::list 的排序 1.1 基础类型以及 std::string 类型的排序 std::list的排序可以通过调用其成员函数sort()来实现。sort()函数使用默认的比较操作符(<)对std::list中的元素进行排序。这意味着,如果元素类型定义了<操作符ÿ…...
Scratch 第十六课-弹珠台游戏
第十六课-弹珠台游戏 大家好,今天我们一起做一款弹珠台scratch游戏,我们也可以叫它弹球游戏!这款游戏在刚出来的时候非常火爆。小朋友们要认真学习下! 这节课的学习目标 物体碰撞如何处理转向问题。复习键盘对角色的控制方式。…...
对简单工厂模式、工厂方法模式的思考
目录 1 背景1.1 题目描述1.2 输入描述1.3 输出描述1.4 输入示例1.5 输出示例 2 简单工厂模式3 工厂方法模式4 思考4.1 改进工厂方法模式 1 背景 题目源自:【设计模式专题之工厂方法模式】2.积木工厂 1.1 题目描述 小明家有两个工厂,一个用于生产圆形积木…...
【详识JAVA语言】面向对象程序三大特性之二:继承
继承 为什么需要继承 Java中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是 现实世界错综复杂,事物之间可能会存在一些关联,那在设计程序是就需要考虑。 比如&…...
【剑指offer--C/C++】JZ3 数组中重复的数字
一、题目 二、本人思路及代码 这道题目它要求的时间空间利用率都是n,那么可以考虑创建一个长度为n的数组repeat初始化为0,下标代码出现的数字,下标对应的数组内容代表该下标数字出现的次数。然后遍历提供的数组,每出现一个数字&a…...
基于SpringBoot的在线拍卖系统设计与实现(源码)
项目源码:https://gitee.com/oklongmm/biye2 引言 随着互联网技术的发展,电子商务得以快速发展,其中之一的在线拍卖系统也逐渐得到了广泛的应用。但是,现有的在线拍卖系统在操作复杂性、安全性和稳定性方面存在一定的问题。为了…...
卢森堡比利时土耳其媒体宣发稿助力跨境出海推广新闻营销
【本篇由言同数字科技有限公司原创】随着全球化进程的加速,越来越多的品牌开始考虑在海外市场扩展业务。对于品牌来说,跨境海外推广是必要的,因为它可以帮助品牌打开更大的市场、吸引更多的消费者、提高品牌知名度和形象,并在全球…...
冒泡排序(C语言详解)
原理:从左到右一次比较,如果左侧数字比右侧数字大(小),则两数交换,否则比较下一 组数字,每一次大循环比较可以将乱序的最右侧数字改为最大(最小),…...
STC-ISP原厂代码研究之 V3.7d汇编版本
最近在研究STC的ISP程序,用来做一个上位机烧录软件,逆向了上位机软件,有些地方始终没看明白,因此尝试读取它的ISP代码,但是没有读取成功。应该是目前的芯片架构已经将引导代码放入在了单独的存储块中,而这存储块有硬件级的使能线,在面包板社区-宏晶STC单片机的ISP的BIN文…...
【word】引用文献如何标注右上角
一、在Word文档中引用文献并标注在右上角的具体步骤如下 1、将光标移动到需要添加文献标注的位置: 2、在文档上方的工具栏中选择“引用”选项: 3、点击“插入脚注”或“插入尾注”: ①如果选择的是脚注,则脚注区域会出现在本页的…...
MySQL 5.5、5.6、5.7的主从复制改进
主从复制面临的问题 MySQL一直以来的主从复制都是被诟病,原因是: 1、主从复制效率低 早期mysql的复制是通过将binlog语句异步推送到从库。从库启动一个IO线程将接收到的数据记录到relaylog中;另外启动一个SQL线程负责顺序执行relaylog中的语句实现对数据的拷贝。 这里的…...
性能分析排查思路之日志(1)
本文是性能问题分析排查思路的展开内容之一,主要分为日志1期,机器4期、环境2期共7篇系列文章,本期是第一篇,讲日志的分析方法和经验。 系列文章传送门: 一图梳理性能问题分析排查思路-总体概述(0ÿ…...
Vue中如何实现条件渲染?
在Vue中实现条件渲染非常简单且灵活,主要通过Vue的指令来实现。在Vue中,我们可以使用v-if和v-else指令来根据条件来渲染不同的内容。下面就让我们通过一个简单的示例来演示如何在Vue中实现条件渲染: <!DOCTYPE html> <html lang&qu…...
Postman上传文件的操作方法
前言 调用某个接口,测试上传文件功能。一时间不知如何上传文件,本文做个操作记录,期望与你有益。 步骤一、设置Headers key:Content-Type value:multipart/form-data 步骤二、设置Body 选择form-data key:file下拉框选择file类型value&…...
linux系统Jenkins工具介绍
Jenkins概念介绍 Jenkins概念Jenkins目的特性产品发布流程 Jenkins概念 Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台。这是一个免费的源代码,可以处理任何类型的构建或持续集成。集成Jenkins可以用于一些…...
【python】遵守 robots.txt 规则的数据爬虫程序
程序1 编写一个遵守 robots.txt 规则的数据爬虫程序涉及到多个步骤,包括请求网页、解析 robots.txt 文件、扫描网页内容、存储数据以及处理异常。由于编程语言众多,且每种语言编写爬虫程序的方式可能有所不同,以下将使用 Python 语言举例&am…...
使用爬虫去获取四六级成绩
使用爬虫去获取四六级成绩 今天出成绩,没过,二战六级依然惨死,那么我就写一个简单的爬虫,其实也可以封装成一个接口的,然后直接输入姓名 身份证好 以及四六级即可获取成绩,我就是简单的玩了一下哈…...
洛谷P1256 显示图像
广搜练手题 题目链接 思路 打印每个数与其最近的 1 1 1的曼哈顿距离,显然广搜,存储每一个 1 1 1,针对每一个 1 1 1开始广搜,逐层更新,每轮后更新的为两轮之中的最小曼哈顿距离 ACcode #include<bits/stdc.h>…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
