二十二、状态模式

文章目录

  • 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 总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/403480.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树练习习题集一(Java)

1. 思路&#xff1a; 就是让左孩子和右孩子进行交换&#xff0c;这里需要一个中间变量用来记录&#xff0c;然后完成交换。如果进行优化则添加当左孩子和右孩子都为null时直接返回。 class Solution {public TreeNode invertTree(TreeNode root) {TreeNode tmpnull;//用来进行…

网络原理知识总结

一、网络模型 1.1 osi七层参考模型 物理层&#xff1a;连接通信链路、传输比特流数据链路层&#xff1a;数据封装成帧&#xff0c;在节点与节点间实现可靠物理地址寻址&#xff0c;进行差错校验、流量控制网络层&#xff1a;逻辑地址寻址&#xff0c;路由选择 IP(IPV4IPV6) I…

window.onload、$(document).ready()、Vue.created() 页面加载完成后执行方法

1、JavaScript 的 window.onload 方法 window.onload 方法是在页面所有元素&#xff08;包括图片、样式、链接等&#xff09;加载完成后触发的&#xff0c;在这个事件之前&#xff0c;页面上的所有资源都必须加载完成。因此&#xff0c;如果页面中包含大量的图片或其他资源&am…

【iOS】——响应者链和事件传递链

事件传递 事件传递流程 发生触摸事件后&#xff0c;系统会将该事件封装成UIEvent对象加入到一个由UIApplication管理的事件队列 UIApplication会从事件队列中取出最前面的事件&#xff0c;并将事件分发下去以便处理&#xff0c;通常&#xff0c;先发送事件给应用程序的主窗口…

TCP详解(一)报文详情/MSS/MTU

本文旨在介绍TCP的报文格式详情和传输层、链路层的字节数限制 1 TCP 协议的报文格式 TCP 报文段包括协议首部和数据两部分&#xff0c;协议首部的固定部分是 20 个字节&#xff0c;头部是固定部分&#xff0c;后面是选项部分。 1.1 端口号 16位源端口&#xff1a;发送方主机…

KDP数据平台:以实战案例验证技术领先力

本文由智领云 LeetTools 工具自动生成 申请试用&#xff1a; https://www.leettools.com/feedback/ 在当今快速发展的技术环境中&#xff0c;数据平台的选择对企业的数字化转型和业务发展至关重要。智领云开源KDP&#xff08;Kubernetes Data Platform&#xff09;在数据处理和…

效果炫酷的3D翻转书特效WordPress主题模板MagicBook主题v1.19

正文&#xff1a; MagicBook是一款支持3D翻书特效的书籍WordPress主题。支持可视化页面搭建&#xff0c;3D菜单&#xff0c;完全自适应设计,WPML多语言支持。 这款主题一定会让你爱不释手。虽然他是英文的&#xff0c;但不可不承认的是&#xff0c;它优雅的设计会让你愿意花时…

无缝融入,即刻智能[二]:Dify-LLM平台(聊天智能助手、AI工作流)快速使用指南,42K+星标见证专属智能方案

无缝融入,即刻智能[二]:Dify-LLM平台(聊天智能助手、AI工作流)快速使用指南,42K+星标见证专属智能方案 1.快速创建应用 你可以通过 3 种方式在 Dify 的工作室内创建应用: 基于应用模板创建(新手推荐) 创建一个空白应用 通过 DSL 文件(本地 / 在线)创建应用 从模板创建…

13 定时器

13 定时器 1、定时1.1 硬件定时器的特性1.2 硬件定时器对应的中断处理函数所作的工作(了解)1.3 linux内核中跟时间相关的三个概念&#xff1a; 2、延时2.1.延时定义2.2 忙等待2.3.休眠等待2.4 等待队列机制2.4.1 介绍2.4.2 结论2.4.3 进程休眠和唤醒的编程步骤方法 1方法 2 3、…

关于uniapp使用izExif.js 插件问题

需求&#xff1a;1.APP获取图片的属性&#xff0c;得到经纬度信息&#xff0c;然后标注到图片上 我们采用izExif.js 插件&#xff0c;进行获取图片信息&#xff0c;在模拟器测试好好地&#xff0c;但是使用真机测试发现getImageData没有返回信息&#xff0c;去izExif.js源码查…

ubuntu中python 改为默认使用python3,pip改为默认使用pip3

一、安装pip和python&#xff08;有的话可跳过&#xff09; 更新软件源 sudo apt update !!!apt和apt-get apt apt-get、apt-cache 和 apt-config 中最常用命令选项的集合。 部分截图为apt-get&#xff0c;建议直接用apt 安装pip和python ubuntu 18.04和更高版本默认安…

字符串金额转换,字符串手机号屏蔽,身份证信息查看,敏感词替换

2135 在发票上面该写成零佰零拾零万贰仟壹佰叁拾伍元 我们用逆推法可以写成零零零贰壹叁伍->贰壹叁伍->2135 1.遍历获取到每一个数字&#xff0c;然后把大写放到数组里面&#xff0c;将数字当作索引&#xff0c;在数组里面查找大写 package stringdemo;import java.uti…

Jakarta Servlet 到 SpringMVC

Jakarta EE&#xff08;曾被称为Java EE&#xff09;是Java平台企业版&#xff08;Java Platform Enterprise Edition&#xff09;的下一代版本&#xff0c;它在Oracle将Java EE的开发和维护交给Eclipse Foundation后得以重生&#xff0c;并更名为Jakarta EE。Jakarta EE保留了…

Windows采用VS2019实现Open3D的C++应用

1、参考链接 https://blog.csdn.net/qq_31254435/article/details/137799739 但是&#xff0c;我的方法和上述链接不大一样&#xff0c;我是采用VS2019进行编译的&#xff0c;方便在Windows平台上验证各种算法。 2、创建一个VS2019的C Console工程 #include <iostream>…

MT1619 (A/B/C/D 15W-25W)快充电源主控芯片

MT1619 是一款快充电源主控芯片&#xff0c;MT1619内部集成了一颗高集成度、高性能的电流模式 PWM 控制器和一颗功率 MOSFET。MT1619适用于小于 30W 的开关电源。MT1619 具有恒功率功能&#xff0c;特别适用于 PD 充电器、电源适配器等中小功率的开关电源设备。极低的启动电流与…

windows下TortoiseSVN切换账号的方法

前言 在项目开始初期的时候大家会使用一个默认账号,后面会根据需要给每个人分配各自的个人账号,这个时候就需要重登陆新的svn账号,下面就是讲解下怎样在windows下修改登录TortoiseSVN的账号。 方法 1.首先在桌面右键&#xff0c;选择TortoiseSVN-settings 2.进入设置页面&a…

阿里云注册、认证、短信资质、签名、模板申请过程

一、帐号注册 输入“帐号密码注册”中的相关信息即可。 手机号是必须的&#xff0c;先确定好手机号。 正常的可以直接注册成功的。 二、实名认证 注册成功之后&#xff0c;就可以点击上述的“快速实名认证”。 这次选择的是“企业认证”。 有几种方式&#xff0c;如下&#x…

clamp靶机复现

靶机设置 设置靶机为NAT模式 靶机IP发现 nmap 192.168.112.0/24 靶机IP为192.168.112.143 目录扫描 dirsearch 192.168.112.143 访问浏览器 提示让我们扫描更多的目录 换个更大的字典&#xff0c;扫出来一个 /nt4stopc/ 目录 目录拼接 拼接 /nt4stopc/ 发现页面中有很多…

CeresPCL 岭回归拟合(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 由于在使用最小二乘插值拟合时,会涉及到矩阵求逆的操作,但是如果这个矩阵接近于奇异时,那么拟合的结果就会与我们期望的结果存在较大差距,因此就有学者提出在最小二乘的误差函数中添加正则项,即: 这里我们也可…

【SpringBoot】SpringBoot框架的整体环境搭建和使用(整合Mybatis,Druid,Junit4,PageHelper,logback等)

目录 1.介绍 1.1 配置文件 1.2 目录结构 2.基于SpringBoot的SpringMVC 4.整合Mybatis 5.整合Druid连接池 6.整合Junit4 7.整合Logback 8.整合PageHelper 9.SpringBoot整合Thymeleaf ​编辑 【附录】springboot的pom.xml 1.介绍 Spring框架的优点是方便解耦、简化开…