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

二十二、状态模式

文章目录

  • 1 基本介绍
  • 2 案例
    • 2.1 Season 接口
    • 2.2 Spring 类
    • 2.3 Summer 类
    • 2.4 Autumn 类
    • 2.5 Winter 类
    • 2.6 Person 类
    • 2.7 Client 类
    • 2.8 Client 类的运行结果
    • 2.9 总结
  • 3 各角色之间的关系
    • 3.1 角色
      • 3.1.1 State ( 状态 )
      • 3.1.2 ConcreteState ( 具体的状态 )
      • 3.1.3 Context ( 上下文 )
      • 3.1.4 Client ( 客户端 )
    • 3.2 类图
  • 4 注意事项
  • 5 优缺点
  • 6 适用场景
  • 7 总结


1 基本介绍

状态模式(State Pattern)是一种 行为型 设计模式,它 允许一个对象在其内部状态改变时改变它的行为,使得这个对象 看起来像是修改了它的类

2 案例

本案例显示了 人 在 不同的季节 中 享受不同的假期 和 穿不同的上衣 的情况,季节的变化通过月份的变化而实现。

2.1 Season 接口

public interface Season { // 季节String getName(); // 季节名称void festivals(); // 节日情况void dress(); // 上衣的穿着情况
}

2.2 Spring 类

public class Spring implements Season { // 春季// 单例模式private static final Spring SPRING = new Spring();private Spring() {}public static Spring getInstance() {return SPRING;}@Overridepublic String getName() {return "春季";}@Overridepublic void festivals() {System.out.println("春节、元宵节、清明节。");}@Overridepublic void dress() {System.out.println("从 棉袄 向 短袖 过渡。");}
}

2.3 Summer 类

public class Summer implements Season { // 夏季// 单例模式private static final Summer SUMMER = new Summer();private Summer() {}public static Summer getInstance() {return SUMMER;}@Overridepublic String getName() {return "夏季";}@Overridepublic void festivals() {System.out.println("端午节、劳动节。");}@Overridepublic void dress() {System.out.println("穿短袖。");}
}

2.4 Autumn 类

public class Autumn implements Season { // 秋季// 单例模式private static final Autumn autumn = new Autumn();private Autumn() {}public static Autumn getInstance() {return autumn;}@Overridepublic String getName() {return "秋季";}@Overridepublic void festivals() {System.out.println("中秋节、重阳节。");}@Overridepublic void dress() {System.out.println("从 短袖 向 棉袄 过渡。");}
}

2.5 Winter 类

public class Winter implements Season { // 冬季// 单例模式private static final Winter INSTANCE = new Winter();private Winter() {}public static Winter getInstance() {return INSTANCE;}@Overridepublic String getName() {return "冬季";}@Overridepublic void festivals() {System.out.println("冬至、腊八节、除夕。");}@Overridepublic void dress() {System.out.println("穿棉袄。");}
}

2.6 Person 类

public class Person { // 人private int month; // 月份private Season season; // 月份对应的季节public void setMonth(int month) { // 设置月份和对应的季节if (month < 1 || month > 12) {throw new IllegalArgumentException("请输入正确的月份");}this.month = month;if (month >= 2 && month < 5) {season = Spring.getInstance();} else if (month >= 5 && month < 8) {season = Summer.getInstance();} else if (month >= 8 && month < 11) {season = Autumn.getInstance();} else {season = Winter.getInstance();}}public void showMonth() { // 显示月份和季节的情况System.out.println("=================="+ month + "月是" + season.getName()+ "==================");}public void showNotAttendClass() { // 显示不上课的情况,除了周末和寒暑假之外System.out.print("不上课的日子有:");season.festivals();}public void showDress() { // 显示上衣的穿着情况System.out.print("上衣的穿着情况:");season.dress();}
}

2.7 Client 类

public class Client { // 客户端,测试了 人在每个月 不上课的情况 和 上衣的穿着情况public static void main(String[] args) {Person person = new Person();// 每隔 1 秒增加 1 个月for (int month = 1; month <= 12; month++) {person.setMonth(month);person.showMonth();person.showNotAttendClass();person.showDress();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

2.8 Client 类的运行结果

==================1月是冬季==================
不上课的日子有:冬至、腊八节、除夕。
上衣的穿着情况:穿棉袄。
==================2月是春季==================
不上课的日子有:春节、元宵节、清明节。
上衣的穿着情况:从 棉袄 向 短袖 过渡。
==================3月是春季==================
不上课的日子有:春节、元宵节、清明节。
上衣的穿着情况:从 棉袄 向 短袖 过渡。
==================4月是春季==================
不上课的日子有:春节、元宵节、清明节。
上衣的穿着情况:从 棉袄 向 短袖 过渡。
==================5月是夏季==================
不上课的日子有:端午节、劳动节。
上衣的穿着情况:穿短袖。
==================6月是夏季==================
不上课的日子有:端午节、劳动节。
上衣的穿着情况:穿短袖。
==================7月是夏季==================
不上课的日子有:端午节、劳动节。
上衣的穿着情况:穿短袖。
==================8月是秋季==================
不上课的日子有:中秋节、重阳节。
上衣的穿着情况:从 短袖 向 棉袄 过渡。
==================9月是秋季==================
不上课的日子有:中秋节、重阳节。
上衣的穿着情况:从 短袖 向 棉袄 过渡。
==================10月是秋季==================
不上课的日子有:中秋节、重阳节。
上衣的穿着情况:从 短袖 向 棉袄 过渡。
==================11月是冬季==================
不上课的日子有:冬至、腊八节、除夕。
上衣的穿着情况:穿棉袄。
==================12月是冬季==================
不上课的日子有:冬至、腊八节、除夕。
上衣的穿着情况:穿棉袄。

2.9 总结

本案例让四个季节对应四个类,并且都实现了 Season 接口,从而能够通过调用 Season 的接口来动态地调用具体季节的方法,很好地利用了面向对象的 多态性,避免了很多判断分支语句,使得编写代码时更简单。

此外,由于四个具体的季节类中没有成员字段,所以使用 单例模式 来创建它们的对象实例。

3 各角色之间的关系

3.1 角色

3.1.1 State ( 状态 )

该角色负责 定义 根据不同状态进行不同处理的 接口。本案例中,Season 接口扮演了该角色。

3.1.2 ConcreteState ( 具体的状态 )

该角色负责 实现 State 角色定义的 接口。本案例中,Spring, Summer, Autumn, Winter 类都在扮演该角色。

3.1.3 Context ( 上下文 )

该角色负责 持有表示当前状态的 ConcreteState 角色的实例对象,并 定义供外部使用的接口。本案例中,Person 类扮演了该角色。

3.1.4 Client ( 客户端 )

该角色负责 使用 Context 角色完成具体的业务逻辑。本案例中,Client 类扮演了该角色。

3.2 类图

alt text
说明:

  • 有时候 State 可以使用抽象类实现,只需要注意 单继承 即可。
  • Context 表面上聚合了 State,实际上根据具体情况会聚合不同的 ConcreteState。
  • Client 可能不会直接使用 State 和 ConcreteState,而是给 Context 传递一个变量,Context 根据这个变量修改自身的状态,就像本案例一样,Client 类给 Person 类的 setMonth() 方法传递 月份 这个参数,从而修改 Person 类内部聚合的 season 对象。

4 注意事项

  • 避免过多状态:虽然状态模式可以处理多个状态,但过多的状态会使系统变得复杂,增加维护难度。因此,在设计时应尽量控制状态的数量,避免状态爆炸。
  • 遵守单一职责原则:每个 ConcreteState 应该只负责一种状态的行为,避免将多个状态的行为放在同一个类中。
  • 避免复杂逻辑:ConcreteState 中的逻辑应该尽量简单,避免在 ConcreteState 中实现复杂的业务逻辑。复杂的逻辑应该由 Context 或其他类来处理。
  • 性能考虑:虽然状态模式可以提高代码的可读性和可维护性,但在某些情况下,由于 需要频繁地创建和销毁状态对象可能会降低系统的性能。因此,应该避免不必要的对象创建和销毁,可以考虑使用 单例模式享元模式 来避免创建过多的对象。
  • 状态转换的管理:状态转换有两种管理方式,在使用本模式时需要选择具体的管理方式。
    • 在 Context 中管理
      • 优点:提高 ConcreteState 的独立性,程序的整体结构会更加清晰。
      • 缺点:Context 必须了解所有 ConcreteState。
    • 在各个 ConcreteState 中管理
      • 优点:每个 ConcreteState 都知道在什么情况下进行状态转换。
      • 缺点:每个 ConcreteState 都必须了解所有 ConcreteState。

5 优缺点

优点

  • 提高代码的可读性和可重用性:状态模式通过明确的 ConcreteState 来表示不同的状态,使得代码更加易于理解和重用。其他对象或系统也可以通过 State 与 ConcreteState 进行交互,而不需要关心具体的状态实现,从而提高了代码的 可读性可重用性
  • 增强系统的可维护性:由于每个 ConcreteState 都封装了与特定状态相关的行为,因此当需要修改某个状态的行为时,只需要修改该 ConcreteState 的代码即可,而不会影响到其他 ConcreteState 或 Context 的代码,从而增强了系统的 可维护性
  • 增强系统的扩展性:当需要添加新的状态时,只需要新增一个 ConcreteState,并在 Context 中修改状态转换的逻辑即可,而不需要修改其他 ConcreteState 的代码,这符合开闭原则(对扩展开放,对修改关闭),从而增强了系统的 扩展性

缺点

  • 增加类的数量:状态模式会引入大量的 ConcreteState,这可能会增加系统的复杂性和类的数量。当状态数量较多时,系统的维护成本也会相应增加。
  • 状态转换的逻辑可能变得复杂:在某些情况下,状态之间的转换逻辑可能非常复杂,这可能会导致 ConcreteState 的代码变得难以理解和维护。此外,如果状态转换的逻辑不恰当,还可能导致系统出现错误或不一致的行为。
  • 对开闭原则的支持有限:虽然状态模式在一定程度上支持开闭原则,但在某些情况下,添加 新的状态 或 修改状态转换的逻辑 仍然需要修改 ConcreteState 的代码,这可能会违反开闭原则,使得系统的扩展性受到一定的限制。

6 适用场景

  • 多状态行为:当 一个对象具有多种状态并且这些状态会影响其行为 时,可以使用状态模式。每个状态对应一个 ConcreteState,封装了在该状态下对象的行为。
  • 状态转换复杂:如果 对象的状态转换逻辑非常复杂并且这些转换逻辑分散在多个地方(如多个条件语句或方法中),那么使用状态模式可以将这些逻辑集中管理,使代码更加清晰和易于维护。
  • 实现状态机:状态模式是实现 状态机 的一种有效方式。状态机是 一种用于描述系统在不同状态下如何响应不同事件的模型。状态模式允许将状态机的各个状态作为独立的类来实现,并通过状态转换来模拟状态机的行为。

7 总结

状态模式 是一种 行为型 设计模式,它使用 多态性 来区分对象在不同状态下的不同行为,避免了在多处书写多重分支语句的复杂性。在本模式中,对象的 状态转换 是一个重点,使用本模式之前需要明确对象的状态应该在合适变化。本模式在生产中比较常用,因为现实生活中有很多实体需要有状态的概念,例如用户的标签。

相关文章:

二十二、状态模式

文章目录 1 基本介绍2 案例2.1 Season 接口2.2 Spring 类2.3 Summer 类2.4 Autumn 类2.5 Winter 类2.6 Person 类2.7 Client 类2.8 Client 类的运行结果2.9 总结 3 各角色之间的关系3.1 角色3.1.1 State ( 状态 )3.1.2 ConcreteState ( 具体的状态 )3.1.3 Context ( 上下文 )3.…...

Spark环境搭建-Local

目录 Local下的角色分布&#xff1a; Anaconda On Linux 安装 (单台服务器) 1.下载安装 2.国内源 下载Spark安装包 1.下载 2.解压 3.环境变量 测试 监控 Local下的角色分布&#xff1a; 资源管理&#xff1a; Master&#xff1a;Local进程本身 Worker&#xff1a;L…...

使用FModel提取黑神话悟空的资产

使用FModel提取黑神话悟空的资产 前言设置效果展示闲聊可能遇到的问题没有相应的UE引擎版本选项 前言 黑神话悟空昨天上线了&#xff0c;解个包looklook。 本文内容比较简洁&#xff0c;仅介绍解包黑神话所需的专项配置&#xff0c;关于FModel的基础使用流程&#xff0c;请见…...

MYSQL定时任务使用手册

开发和管理数据库时&#xff0c;经常需要定时执行某些任务&#xff0c;比如每天备份数据库、每周统计报表等。MySQL提供了一个非常有用的工具&#xff0c;即事件调度器&#xff08;Event Scheduler&#xff09;&#xff0c;可以帮助我们实现定时任务调度的功能。本文将介绍如何…...

SAP 预扣税配置步骤文档【Withholding Tax]

1. 配置预扣税的基本概念 预扣税是对某些支付进行扣除的税&#xff0c;可能适用于各种财务交易&#xff08;例如&#xff0c;供应商支付、股息支付等&#xff09;。预扣税通常包括几种类型&#xff0c;如个人所得税、企业所得税和其他税务种类。 2. 配置步骤 以下是一般的预…...

Ubuntu ssh配置

下面给出配置和使用ubuntu ssh的指南。 环境 Ubuntu22.04 安装Install sudo apt update && sudo apt upgrade sudo apt install openssh-server使用start service ssh status sudo systemctl enable --now ssh sudo ufw allow ssh连接Connect search "conn…...

Spring Boot OAuth2.0应用

本文展示Spring Boot中&#xff0c;新版本OAuth2.0的简单实现&#xff0c;版本信息&#xff1a; spring-boot 2.7.10 spring-security-oauth2-authorization-server 0.4.0 spring-security-oauth2-client 5.7.7 spring-boot-starter-oauth2-resource-server 2.7.10展示三个服务…...

Java | Leetcode Java题解之第363题矩形区域不超过K的最大数值和

题目&#xff1a; 题解&#xff1a; class Solution {public int maxSumSubmatrix(int[][] matrix, int k) {int ans Integer.MIN_VALUE;int m matrix.length, n matrix[0].length;for (int i 0; i < m; i) { // 枚举上边界int[] sum new int[n];for (int j i; j <…...

AI作画提示词(Prompts)工程:技巧与最佳实践

在人工智能领域&#xff0c;AI作画已成为一个令人兴奋的创新点&#xff0c;它结合了艺术与科技&#xff0c;创造出令人惊叹的视觉作品。本文将探讨在使用AI作画时的提示词工程&#xff0c;提供技巧与最佳实践。 理解AI作画 AI作画通常依赖于深度学习模型&#xff0c;尤其是生成…...

leetcode滑动窗口问题

想成功先发疯&#xff0c;不顾一切向前冲。 第一种 定长滑动窗口 . - 力扣&#xff08;LeetCode&#xff09;1456.定长子串中的元音的最大数目. - 力扣&#xff08;LeetCode&#xff09; No.1 定长滑窗套路 我总结成三步&#xff1a;入-更新-出。 1. 入&#xff1a;下标为…...

QT 控件使用案例

常用控件 表单 按钮 Push Button 命令按钮。Tool Button&#xff1a;工具按钮。Radio Button&#xff1a;单选按钮。Check Box&#xff1a;复选框按钮。Command Link Button&#xff1a;命令链接按钮。Dialog Button Box&#xff1a;按钮盒。 容器组控件(Containers) Group Box…...

【MySQL 10】表的内外连接 (带思维导图)

文章目录 &#x1f308; 一、内连接⭐ 0. 准备工作⭐ 1. 隐式内连接⭐ 2. 显式内连接 &#x1f308; 二、外连接⭐ 0. 准备工作⭐ 1. 左外连接⭐ 2. 右外连接 &#x1f308; 一、内连接 内连接实际上就是利用 where 子句对两张表形成的笛卡儿积进行筛选&#xff0c;之前所有的…...

【C语言】:与文件通信

1.文件是什么&#xff1f; 文件通常是在磁盘或固态硬盘上的一段已命名的存储区。C语言把文件看成一系列连续的字节&#xff0c;每个字节都能被单独的读取。这与UNIX环境中&#xff08;C的 发源地&#xff09;的文件结构相对应。由于其他环境中可能无法完全对应这个模型&#x…...

HTTPS通讯全过程

HTTPS通讯全过程 不得不说&#xff0c;https比http通讯更加复杂惹。在第一次接触https代码的时候&#xff0c;不知道为什么要用用证书&#xff0c;公钥是什么&#xff1f;私钥是什么&#xff1f;他们作用是什么&#xff1f;非对称加密和对称加密是啥&#xff1f;天&#xff0c;…...

建筑物规则化(实现) --- 特征边分组、重构、直角化

规则化建筑物 一、摘 要 建筑物多边形在地图综合中的两类处理模型:化简与直角化。 建筑物矢量数据来源广泛&#xff0c;在数据获取过程中&#xff0c;受GPS精确度、遥感影像分辨率或人为因素的影响&#xff0c;数据往往存在不同程度的误差。其中&#xff0c;图像分割、深度学习…...

pytorch的优化

在pytorch中&#xff0c;tensor是基于numpy与array的。内存共享。 在pythorch中&#xff0c;自定义层是继承nn.Module。将层与模型看成是模块&#xff0c;层与模型堪称模块&#xff0c;两者之间没有明确界限&#xff0c;定义方式与定义模型一样_init_与forward。 1、先定义全…...

React 入门第一天:从Vue到React的初体验

作为一名合格的前端工程师&#xff0c;怎么能只会Vue呢&#xff1f;学习React不仅是一场新技术的探索&#xff0c;更是对前端开发思维的一次重新审视。在这里&#xff0c;我将分享学习React的心得&#xff0c;希望能帮助那些和我一样从Vue转向React的开发者。 1. 为什么选择Re…...

Golang | Leetcode Golang题解之第357题统计各位数字都不同的数字个数

题目&#xff1a; 题解&#xff1a; func countNumbersWithUniqueDigits(n int) int {if n 0 {return 1}if n 1 {return 10}ans, cur : 10, 9for i : 0; i < n-1; i {cur * 9 - ians cur}return ans }...

【Linux】 gdb-调试器初入门(简单版使用)

&#x1f525;系列文章&#xff1a;《Linux入门》 目录 一、背景 二、什么是GDB &#x1f337;定义 &#x1f337;GDB调试工具---提供的帮助 三、GDB的安装教程-Ubuntu &#x1f337;gdb的安装 四、哪类程序可被调试 &#x1f337;程序的发布方式 &#x1f337;Debug版…...

Spring 的事务支持

文章目录 1、Spring如何管理事务2、编程式事务1_基本用法2_创建TransactionTemplate实例3_TransactionTemplate的内部结构4_总结 3、声明式事务1_使用Transactional注解2_事务的传播行为3_配置4_总结 1、Spring如何管理事务 Spring为事务管理提供了一致的编程模板&#xff0c;…...

037、LVGL动画类型与参数配置

LVGL动画类型与参数配置 上周帮一个做智能家居面板的客户调试,遇到个挺典型的坑:他用了lv_anim_set_path_cb()自定义了一个缓动曲线,结果动画跑起来像抽风一样忽快忽慢。我让他把回调函数贴出来一看——好家伙,路径函数里直接调了lv_anim_set_time()改时长。这种在动画执行…...

BilibiliDown:5步快速下载B站视频的免费跨平台神器

BilibiliDown&#xff1a;5步快速下载B站视频的免费跨平台神器 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/bi/B…...

Silk v3解码器终极指南:高效转换微信QQ语音为MP3格式

Silk v3解码器终极指南&#xff1a;高效转换微信QQ语音为MP3格式 【免费下载链接】silk-v3-decoder [Skype Silk Codec SDK]Decode silk v3 audio files (like wechat amr, aud files, qq slk files) and convert to other format (like mp3). Batch conversion support. 项目…...

从basicfwd到自定义发包器:手把手教你用DPDK 21.11写一个高性能发包程序

从basicfwd到自定义发包器&#xff1a;DPDK 21.11高性能网络编程实战 在当今云计算和边缘计算蓬勃发展的时代&#xff0c;网络性能优化已成为开发者必须面对的挑战。DPDK&#xff08;Data Plane Development Kit&#xff09;作为高性能数据包处理框架&#xff0c;正在被越来越多…...

颠覆性英雄联盟智能助手:如何用League Akari告别繁琐操作,专注游戏核心

颠覆性英雄联盟智能助手&#xff1a;如何用League Akari告别繁琐操作&#xff0c;专注游戏核心 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power &#x1f680;. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit …...

如何5分钟掌握ncmppGui:解锁音乐格式限制的终极免费工具

如何5分钟掌握ncmppGui&#xff1a;解锁音乐格式限制的终极免费工具 【免费下载链接】ncmppGui 一个使用C编写的极速ncm转换GUI工具 项目地址: https://gitcode.com/gh_mirrors/nc/ncmppGui 你是否曾经遇到过这样的情况&#xff1a;从音乐平台下载的歌曲只能在特定应用中…...

COMET终极指南:5个实用技巧掌握神经机器翻译质量评估框架 [特殊字符]

COMET终极指南&#xff1a;5个实用技巧掌握神经机器翻译质量评估框架 &#x1f680; 【免费下载链接】COMET A Neural Framework for MT Evaluation 项目地址: https://gitcode.com/gh_mirrors/com/COMET COMET&#xff08;A Neural Framework for MT Evaluation&#…...

如何在Electron应用中集成Supertonic:实现离线语音功能的完整指南 [特殊字符]️

如何在Electron应用中集成Supertonic&#xff1a;实现离线语音功能的完整指南 &#x1f399;️ 【免费下载链接】supertonic Lightning-Fast, On-Device, Multilingual TTS — running natively via ONNX. 项目地址: https://gitcode.com/GitHub_Trending/sup/supertonic …...

2026年程序员AI工具链完整配置指南:从开发到部署全流程

你的开发环境还在用2023年的工具&#xff1f;醒醒&#xff0c;AI工具链已经迭代了三代了。## 前言作为一个从 Cursor 0.x 版本就开始跟的早期用户&#xff0c;我亲眼见证了AI编程工具从"玩具"变成"生产力核武器"的过程。2026年5月的今天&#xff0c;整个AI…...

面向AI系统的非功能测试:公平性、可解释性与鲁棒性验证

一、引言&#xff1a;当“功能正确”不再是终点在软件测试的早期时代&#xff0c;我们的职责边界相对清晰——功能符合需求文档、性能达到指标、界面无错别字&#xff0c;测试便可宣告完成。然而&#xff0c;当AI系统从实验室的象牙塔走向社会决策的核心地带&#xff0c;这套传…...