当前位置: 首页 > news >正文

状态模式(State)

状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,使其看起来修改了自身所属的类。其别名为状态对象(Objects for States)。

State is a behavior design pattern that allows an object to change its behavior when its internal state changes,
making it appear to have modified the class it belongs to.

在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。
当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
在UML中可以使用状态图来描述对象状态的变化。

结构设计

Context,上下文类,保存了对于一个Concrete State对象(具体状态对象)的引用,并会将所有与该状态相关的工作委派给它。上下文通过状态接口与状态对象交互。
State,状态基类,接口会声明特定于状态的方法。
Concrete State,具体状态类,会自行实现特定于状态的方法。当多个状态中包含相似代码,可以提供一个封装有部分通用行为的中间抽象类。
状态对象可存储对于上下文对象的反向引用。状态对象可以通过该引用从上下文处获取所需信息,并且能触发状态转移。但这可能会带来对象的循环引用,在实际使用时,要通过对象传参的方式使用。
状态模式类图表示如下:
请添加图片描述

状态模式可能看上去与策略模式相似,但有一个关键性的不同——在状态模式中,特定状态知道其他所有状态的存在,且能触发从一个状态到另一个状态的转换,而策略则几乎完全不知道其他策略的存在。

伪代码实现

接下来将使用代码介绍下状态模式的实现。

// 1、State,状态接口,声明特定于状态的方法
public interface IState {void handle(StateContext context);void doSomething();
}// 2、具体状态类,会自行实现特定于状态的方法,这里特定状态知道其他所有状态的存在,且能触发从一个状态到另一个状态的转换
public class ConcreteStateA implements IState {private static ConcreteStateA state;// 这里的单例实现暂不考虑并发场景public static IState getInstance() {if (state == null) {state = new ConcreteStateA();}return state;}@Overridepublic void handle(StateContext context) {doSomething();context.setCurrentState(ConcreteStateB.getInstance());}@Overridepublic void doSomething() {System.out.println("do some thing in the concrete A instance");}
}
public class ConcreteStateB implements IState {private static ConcreteStateB state;// 这里的单例实现暂不考虑并发场景public static IState getInstance() {if (state == null) {state = new ConcreteStateB();}return state;}@Overridepublic void handle(StateContext context) {doSomething();context.setCurrentState(ConcreteStateA.getInstance());}@Overridepublic void doSomething() {System.out.println("do some thing in the concrete B instance");}
}// 3、状态上下文类,保存了对于一个Concrete State对象(具体状态对象)的引用,并会将所有与该状态相关的工作委派给它。  
// 上下文通过状态接口与状态对象交互。  
public class StateContext {private IState currentState;public StateContext(IState defaultState) {this.currentState = defaultState;}public IState getCurrentState() {return this.currentState;}public void setCurrentState(IState newState) {this.currentState = newState;}public void request() {currentState.handle(this);}
}// 4、客户端
public class StateClient {public void test() {StateContext stateContext = new StateContext(new ConcreteStateA());stateContext.request();stateContext.request();stateContext.request();}
}

适用场景

在以下情况下可以考虑使用状态模式:
(1) 对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可以考虑使用状态模式。
(2) 代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,
使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。
(3) 当相似状态和基于条件的状态机转换中存在许多重复代码时,可考虑使用状态模式。状态模式能够生成状态类层次结构,通过将公用代码抽取到抽象基类中来减少重复。

优缺点

状态模式有以下优点:
(1) 封装了转换规则。调用方无需关心状态转换的实现。
(2) 符合开闭原则。无需修改已有状态类和上下文就能引入新状态。
(3) 符合单一职责原则。将与特定状态相关的代码放在单独的类中。
(4) 消除了可能存在的条件语句。通过消除臃肿的状态机条件语句简化上下文代码。
(5) 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
但是该模式也存在以下缺点:
(1) 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。
(2) 增加系统类和对象的个数。
(3) 实现较为复杂,如果使用不当将导致程序结构和代码的混乱。
(4) 对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

参考

《设计模式 可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著, 李英军, 马晓星等译
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/state.html 状态模式
https://refactoringguru.cn/design-patterns/state 状态模式
https://www.runoob.com/design-pattern/state-pattern.html 状态模式
https://www.cnblogs.com/adamjwh/p/10926952.html 简说设计模式——状态模式

相关文章:

状态模式(State)

状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,使其看起来修改了自身所属的类。其别名为状态对象(Objects for States)。 State is a behavior design pattern that allows an object to change its behavior when its inter…...

【uniapp】样式合集

1、修改uni-data-checkbox多选框的样式为单选框的样式 我原先是用的单选&#xff0c;但是单选并不支持选中后&#xff0c;再次点击取消选中&#xff1b;所以我改成了多选&#xff0c;然后改变多选样式&#xff0c;让他看起来像单选 在所在使用的页面上修改样式即可 <uni-d…...

【Spring框架】SpringBoot统一功能处理

目录 用户登录权限校验用户登录拦截器排除所有静态资源练习&#xff1a;登录拦截器拦截器实现原理 统一异常处理统一数据返回格式为什么需要统⼀数据返回格式&#xff1f;统⼀数据返回格式的实现 用户登录权限校验 用户登录拦截器 1.自定义拦截器 package com.example.demo.…...

51单片机学习--按键控制流水灯模式定时器时钟

TMOD负责确定T0和T1的工作模式&#xff0c;TCON控制T0和T1的启动或停止计数&#xff0c;同时包含定时器状态 TF1&#xff1a;定时器1溢出标志 TF0&#xff1a;定时器0溢出标志 0~65535 每隔1微秒计数器1&#xff0c;总时间65535微秒&#xff0c;赋上初值64535&#xff0c;则只…...

Django教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Django是一个开放源代码的Web应用框架&#xff0c;由Python写成。采用了MTV的框架模式&#xff0c;即模型M&#xff0c;视图V和模版T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的&#xff0c;即是CMS&#xff08;内容管理系统&#xf…...

VGG卷积神经网络-笔记

VGG卷积神经网络-笔记 VGG是当前最流行的CNN模型之一&#xff0c; 2014年由Simonyan和Zisserman提出&#xff0c; 其命名来源于论文作者所在的实验室Visual Geometry Group。 测试结果为&#xff1a; 通过运行结果可以发现&#xff0c;在眼疾筛查数据集iChallenge-PM上使用VGG…...

Python爬虫如何实现IP代理池搭建

大家好&#xff0c;作为一名IP代理产品供应商&#xff0c;我知道很多人在使用Python爬虫时遇到了一些麻烦。有时候&#xff0c;我们的爬虫在爬取过程中会被目标网站识别并封禁IP&#xff0c;导致我们的爬取任务受阻。今天我要分享的就是如何搭建一个高效稳定的IP代理池&#xf…...

单例模式:保证一个类只有一个实例

单例模式&#xff1a;保证一个类只有一个实例 什么是单例模式&#xff1f; 在软件开发中&#xff0c;有些类只需要一个实例&#xff0c;比如数据库连接池、线程池等。单例模式就是一种设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 实…...

【新版系统架构补充】-七层模型

网络功能和分类 计算网络的功能 &#xff1a;数据通信、资源共享、管理集中化、实现分布式处理、负载均衡 网络性能指标&#xff1a;速率、带宽&#xff08;频带宽度或传送线路速率&#xff09;、吞吐量、时延、往返时间、利用率 网络非性能指标&#xff1a;费用、质量、标准化…...

第2章 C语言概述

本章介绍以下内容&#xff1a; 运算符&#xff1a; 函数&#xff1a;main()、printf() 编写一个简单的C程序 创建整型变量&#xff0c;为其赋值并在屏幕上显示其值 换行字符 如何在程序中写注释&#xff0c;创建包含多个函数的程序&#xff0c;发现程序的错误 什么是关键字 C程…...

vscode vue3开发常用插件(附Prettier格式化配置)

必不可少插件(名称可能不全)&#xff1a; 1、Chinese (Simplified) (简体中文) Language 2、Prettier - Code formatter 3、Vue 3 Snippets 4、Vue Language Features (Volar) 可选插件&#xff1a; 5、Auto Close Tag 6、Vue Theme Prettier格式化配置&#xff1a; 按ctr…...

【微信小程序】van-uploader实现文件上传

使用van-uploader和wx.uploadFile实现文件上传&#xff0c;后端使用ThinkPHP。 1、前端代码 json&#xff1a;引入van-uploader {"usingComponents": {"van-uploader": "vant/weapp/uploader/index"} }wxml&#xff1a;deletedFile是删除文件函…...

人工智能在计算机视觉中的应用与挑战

引言 计算机视觉是人工智能领域的一个重要分支&#xff0c;旨在让计算机能够像人一样理解和解释视觉信息&#xff0c;实现图像和视频的自动识别、理解和分析。计算机视觉技术已经在许多领域产生了深远的影响&#xff0c;如人脸识别、自动驾驶、医学影像分析等。本篇博客将深入…...

以太网接口指示灯状态分析和电路设计

一、RJ45以太网连接器介绍 以带网络隔离变压器的RJ45接头为例&#xff0c;如HR911105A&#xff0c;其技术参数如下 原理框图 指示灯部分 二、PHY芯片 phy芯片以DP83848CVV/NOPB为例&#xff0c;查看数据手册。引脚26&#xff0c;引脚27和引脚28和LED灯相关&#xff0c;如下截…...

Redis的基础

一、进入redis 内部 / 关闭 # 方式一&#xff1a; // 进入redis redis-cli // 有密码输入密码 &#xff1a;auth [username] password auth 123456 # 方式二&#xff1a; // 进入redis 并且输入密码 redis-cli -a 123456// 如果在docker 里面的则可以 docker exec -it redis…...

LeetCode 626. 换座位

题目链接&#xff1a;LeetCode 626. 换座位 题目描述 表名&#xff1a;Seat 编写SQL查询来交换每两个连续的学生的座位号。如果学生的数量是奇数&#xff0c;则最后一个学生的id不交换。 按 id 升序 返回结果表。 查询结果格式如下所示。 示例1&#xff1a; 题目分析 如…...

华为、阿里巴巴、字节跳动 100+ Python 面试问题总结(六)

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python面试专栏&#xff1a;《Python面试》此专栏面向准备面试的2024届毕业生。欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; …...

hash 模式和 history 模式的实现原理

hash 模式和 history 模式的实现原理&#xff1a; #后面的 hash 值的变化不会导致浏览器向服务器发出请求&#xff0c;浏览器不发出请求&#xff0c;就不会刷新页面。通过监听 hashchange 事件的变化可以知道 hash 值发生了哪些变化&#xff0c;然后根据 hash 值的变化来实现更…...

并发编程Part 2

1. JMM 问题&#xff1a;请你谈谈你对volatile的理解? volitile 是 Java 虚拟机提供的一种轻量级的同步机制 &#xff0c;三大特性&#xff1a; 保证可见性 不保证原子性 禁止指令重排 线程之间如何通信&#xff1f; 通信是指线程之间以如何来交换信息。一般线程之间的通信…...

springboot异步多线程的实现

1、配置线程池相关参数 package com.xxx.test.config;import lombok.extern.slf4j.Slf4j; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...