【设计模式】状态模式

文章目录

  • 引例
  • 状态模式理论
  • 状态模式代码优化
    • 结合享元模式
    • 并发问题解决
  • 策略模式 VS 状态模式

引例

交通信号灯系统的设计与实现
image.png
方案一
传统设计方案
定义交通灯颜色的枚举```

public enum LightColor {
Green,Red,Yellow
}

交通灯类TrafficLight,处理颜色转换等业务逻辑

public class TrafficLight{private LightColor lightColor;// 将信号灯初始化为红灯public TrafficLight(){lightColor = LightColor.Red;}// 信号转换处理public void changeSignal(){if (lightColor == LightColor.Red){System.out.println("红灯停");lightColor = LightColor.Green;}else if (lightColor == LightColor.Green){System.out.println("绿灯行");lightColor = LightColor.Yellow;}else if (lightColor == LightColor.Yellow){System.out.println("黄灯亮了等一等");lightColor = LightColor.Red;}}
}

客户端类

public class Client{public static void main(String[] args){TrafficLight light = new TrafficLight();light.changeSignal();light.changeSignal();light.changeSignal();}
}

运行结果为:

红灯停
绿灯行
黄灯亮了等一等

说明:

  1. TrafficLight类种的if-else条件分支违背开闭原则

方案二
参考策略模式进行修改
image.png
说明:

  1. 将交通灯的展示即display()做成了策略,因而策略类形成了层次类,满足OCP
  2. 具体类满足单一职责
  3. 环境类引用策略完成展示和交通灯颜色切换

代码说明
交通灯层次类

public interface ITrafficLightStrategy {void display();
}public class RedLightStrategy implements ITrafficLightStrategy {@Overridepublic void display() {System.out.println("红灯停");}
}public class GreenLightStrategy implements ITrafficLightStrategy {@Overridepublic void display() {System.out.println("绿灯行");}
}public class YellowLightStrategy implements ITrafficLightStrategy {@Overridepublic void display() {System.out.println("黄灯请等一等");}
}

环境类Context:
在Context类中有一个ITrafficLightStrategy对象,用于控制当前的交通灯颜色,showSignal()方法显示,changeSignalStrategy()方法改变交通灯

public class Context {private ITrafficLightStrategy trafficLightStrategy;public TrafficLight(ITrafficLightStrategy trafficLightStrategy) {this.signalStrategy = signalStrategy;}public void showSignal() {if (signalStrategy != null) {            signalStrategy.displaySignal();}}public void changeSignalStrategy (ITrafficLightStrategy trafficLightStrategy) {this.signalStrategy = signalStrategy;}
}

Client类实现:

public class Client {public static void main(String[] args) {Context context = new Context(new RedLightStrategy());    context.showSignal();context.changeSignalStrategy(new GreenLightStrategy());context.showSignal();context.changeSignalStrategy(new YellowLightStrategy());context.showSignal();}
}

说明:在方案二的设计中交通灯的颜色切换实现是完全暴露给Client的,不符合面向对象的封装特性

方案三
将每种颜色的灯做成一个类,但又不能是像工厂方法模式那样的创建型模式,因为三个灯从始至终都是没有改变的。
这里我们考虑把每种颜色的灯表达为一种状态
image.png
仔细看方案三和方案二的类图差别
在方案三的State.display(Context)方法中有一个Context对象作为参数传递,这表示的是在display()方法中利用Context改变当前交通灯的状态。另外,这也带来了Context类和ITrafficLightState层次类的双向依赖
交通灯的状态切换具体而言是在display()方法中加入以下语句:

//在具体的状态子类中告诉环境对象Context,下一个状态是谁。
context.changeCurrentSignal(new RedLightState());

交通灯接口设计:

public interface ITrafficLightState {
void display(Context context); // 反向关联到Context,取得系统的上下文环境
}

Context类的设计:相比于方案二,changeSignal()方法中具体切换代码从Client类移动到了State类的display()方法中

public class Context {private ITrafficLightState currentState;public Context() {this.currentState = new RedLightState();}public void showSignal() {if (currentState != null) {currentState.display(this); // this表示当前context对象}}public void changeCurrentSignal(ITrafficLightState currentState) {this.currentState = currentState;}
}

Client类的设计:

public class Client {public static void main(String[] args) {Context context = new Context();context.showSignal();context.showSignal();context.showSignal();}
}

状态模式理论

定义:允许状态对象在其内部状态发生改变时改变其行为,通过将抽象有状态的对象,将复杂的状态改变“判断逻辑”提取到不同状态对象中实现
image.png
优点

  1. 解决switch-case、if-else带来的难以维护的问题
  2. 代码结构清晰,提高了扩展性

缺点

  1. 状态扩展导致状态类数量增多
  2. 增加了系统复杂度,使用不当将会导致逻辑的混乱
  3. 不完全满足开闭原则,增加或者删除状态类时,需要修改涉及到的状态转移逻辑和对应的类

应用场景
一个操作的判断逻辑/行为取决于对象的内部状态时

状态模式代码优化

结合享元模式

对象重复创建问题
每次状态切换都需要创建一个新的状态对象,而事实上一个状态对象完全可以只用一个枚举值标识,这带来巨大的额外资源开销。
解决方法
单例模式
享元模式

享元模式代码示例:新增一个Factory创建状态对象的工厂类,在这个Factory类中维护着一个现有的ITrafficLightState状态层次类Map,State类在需要new状态对象时,调用Factory的getTrafficLight方法,如果维护的map中有该类对象,则直接返回;如果没有,则创建一个新的状态对象返回。由此来减少状态模式中的对象重复创建

public class TrafficLightStateFactory {  //享元模式// 共享Mapprivate static Map<Class, ITrafficLightState> lights = new HashMap();public static ITrafficLightState getTrafficLight(Class key) {if(!(lights.containsKey(key))) {try {lights.put(key, (ITrafficLightState) key.getDeclaredConstructor().newInstance());} catch (Exception e) {throw new RuntimeException(e);}}return lights.get(key);}
}

ConcreteState类的对应修改

public class GreenLightState implements ITrafficLightState {@Overridepublic void display(Context context) throws Exception {System.out.println("绿灯行");context.changeCurrentSignal(TrafficLightStateFactory.getTrafficLight(YellowLightState.class));}
}

并发问题解决

由于状态是单例的,可以在多个上下文之间共享。若状态类中持有其他资源就有产生并发问题的可能
于是,我们可以看在前面的方案三设计中,State层次类中对Context类的依赖是来自display()方法的参数,而没有通过属性的方法持有Context对象的引用

策略模式 VS 状态模式

image.png
说明:策略模式持有Context对象一般是需要使用context对象中的数据或方法,如H5所述的使用Context对象的计时方法。

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

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

相关文章

【AMD Xilinx】ZUBoard(3):通过AXI GPIO接收PL端的按键输入

【AMD Xilinx】ZUBoard&#xff08;3&#xff09;&#xff1a;通过AXI GPIO接收PL端的按键输入 一、本项目实现的功能二、Vivado工程1. 添加AXI GPIO2. 配置AXI GPIO3. 根据原理图查找对应管脚4. I/O Planning5.XDC 三、ARM代码1. 地址空间2. 函数说明3. 实际的C代码实现4. 运行…

VitulBox中Ubuntu虚拟机安装JAVA环境——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项

前言 在进行之后操作是请下载好JDK&#xff0c;之后的内容是以Ubuntu虚拟机中安装java环境续写。 提示&#xff1a;以下操作是在虚拟机hadoop用户下操作的&#xff0c;并为安装java环境作准备 一、更新APT 为了确保Hadoop安装过程顺利进行&#xff0c;建议用hadoop用户登录…

基于SpringBoot实现的前后端分离电影评分项目,功能:注册登录、浏览影片、热门影片、搜索、评分、片单、聊天、动态

一、项目介绍 本项目主要基于SpringBoot、Mybatis-plus、MySQL、Redis实现的影片评分项目。 本系统是前后端分离的&#xff0c;分别由三个子项目构成&#xff1a;java服务端、用户前端、管理员管理前端 关键词&#xff1a;springboot java vue mysql reids websocket 毕业设计…

2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项样题卷①

2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项&#xff08;高职组&#xff09; 样题&#xff08;第1套&#xff09; 目录 2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项&#xff08;高职组&#xff09; 样题&#xff08;第1套&#xff09; 模块一…

Java Log 学习笔记

参考文章&#xff1a; 1.Java 日志从入门到实战 2.Java日志框架的发展历史&#xff0c;你不想了解一下吗 背景 想自定义 logback 配置文件进行日志分级别记录到不同文件&#xff0c;遇到了几个问题&#xff08;使用的是 spring-boot 构建的项目&#xff0c;spring-boot 版本为…

多模态大模型-CogVLm 论文阅读笔记

多模态大模型-CogVLm 论文阅读笔记 COGVLM: VISUAL EXPERT FOR LARGE LANGUAGEMODELS 论文地址 :https://arxiv.org/pdf/2311.03079.pdfcode地址 : https://github.com/THUDM/CogVLM时间 : 2023-11机构 : zhipuai,tsinghua关键词: visual language model效果:&#xff08;2023…

MySQL基础入门(二)

多表内容 一对多 这个内容是黑马的入门问题&#xff0c;可以带大家思考一下这个怎么设计 我们要知道一个岗位可以对应很多用户&#xff0c;而一个用户只能对应一个岗位&#xff0c;这就属于一对多的类型 那么我们需要怎么将他们进行关联呢&#xff1f; 现在我们可以通过一个…

蓝桥杯C/C++程序设计——单词分析

题目描述 小蓝正在学习一门神奇的语言&#xff0c;这门语言中的单词都是由小写英文字母组 成&#xff0c;有些单词很长&#xff0c;远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词&#xff0c;他准备不再完全记忆这些单词&#xff0c;而是根据单词中哪个字母出…

Zookeeper 实战 | Zookeeper 和Spring Cloud相结合解决分布式锁、服务注册与发现、配置管理

专栏集锦&#xff0c;大佬们可以收藏以备不时之需&#xff1a; Spring Cloud 专栏&#xff1a;http://t.csdnimg.cn/WDmJ9 Python 专栏&#xff1a;http://t.csdnimg.cn/hMwPR Redis 专栏&#xff1a;http://t.csdnimg.cn/Qq0Xc TensorFlow 专栏&#xff1a;http://t.csdni…

Media Encoder各版本安装指南

Media Encoder 链接地址如下&#xff1a; https://pan.baidu.com/s/1qOowHfm9rhrOOMljYgQCsA?pwd0531 1.鼠标右击【ME2023(64bit)】压缩包选择&#xff08;win11系统需先点击“显示更多选项”&#xff09;【解压到 ME2023(64bit)】。 2.打开解压后的文件夹&#xff0c;鼠标右…

16.综合项目实战

一、基础演练&#xff1a; 1、建库、建表 # 创建数据库 create database mysql_exampleTest; use mysql_exampleTest; # 学生表 CREATE TABLE Student( s_id VARCHAR(20), s_name VARCHAR(20) NOT NULL DEFAULT , s_birth VARCHAR(20) NOT NULL DEFAULT , s_sex VARC…

分布式存储考点梳理 + 高频面试题

欢迎来到分布式存储模环节&#xff0c;本文我将和你一起梳理面试中分布式系统的数据库的高频考点&#xff0c;做到温故知新。 面试中如何考察分布式存储 广义的分布式存储根据不同的应用领域&#xff0c;划分为以下的类别&#xff1a; 分布式协同系统 分布式文件系统 分布式…

运行时错误‘53’文件未找到:MathPage.WLL,安装MathType后Word不能复制粘贴问题的解决

两步解决&#xff1a; 1. 打开Word-->文件-->选项-->信任中心-->信任中心设置-->受信任位置&#xff0c;解决宏问题 添加如下受信任位置&#xff0c; 我的路径&#xff1a;C:\Program Files\Microsoft Office\root\Office16\STARTUP\ 2. 找到MathType下的MathT…

GitHub 一周热点汇总 第3期 (2023/12/24-12/30)

GitHub一周热点汇总第三期 (2023/12/24-12/30)&#xff0c;梳理每周热门的GitHub项目&#xff0c;了解热点技术趋势&#xff0c;掌握前沿科技方向&#xff0c;发掘更多商机。元旦就要到了&#xff0c;提前祝大家新年快乐。 #1 StreamDiffusion 项目名称&#xff1a;StreamDiff…

安装kafka

静态文件安装&#xff08;单机&#xff09; 解压到指定目录&#xff08;解压到 /usr&#xff09; tar -zxf kafka_2.11-2.2.0.tgz -C /usr/ 到指定的解压目录下 cd /usr/kafka_2.11-2.2.0/ 配置主机名 查看是否配置了HOSTNAME vim /etc/sysconfig/network 没有就新增 HOSTNA…

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第二节 栈基本工作原理

深入浅出图解C#堆与栈 C# HeapingVS Stacking第二节 栈基本工作原理 [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第一节 理解堆与栈](https://mp.csdn.net/mdeditor/101021023)[深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第二节 栈基本工作原理](https://mp.cs…

“从零到一“基于Freeswitch二次开发: 应用架构设计(二)

一、架构分享 上一篇文章“从零到一“基于Freeswitch二次开发:Freeswitch入门与网络架构 (一) 对Freeswitch二次开发做了一个介绍&#xff0c;距离这篇文章的发布时间有点久了&#xff0c;之前一直没时间把下文补上来。正好到了年末想起来&#xff0c;就把我们的一个实现架构进…

微服务系列之分布式事务理论

概述 事务是由一组操作构成的可靠的独立的工作单元&#xff0c;事务具备ACID的特性&#xff0c;即原子性、一致性、隔离性和持久性。 分类 大多数情况下&#xff0c;分类是没有意义的一件事。但是分类可以一定程度上&#xff0c;加深理解。 实现 从实现角度来看&#xff0…

软件测试/测试开发丨Python 面向对象编程思想

面向对象是什么 Python 是一门面向对象的语言面向对象编程&#xff08;OOP&#xff09;&#xff1a;Object Oriented Programming 所谓的面向对象&#xff0c;就是在编程的时候尽可能的去模拟真实的现实世界&#xff0c;按照现实世界中的逻辑去处理问题&#xff0c;分析问题中…

【ONE·MySQL || 数据类型 表的约束】

总言 主要内容&#xff1a;介绍MySQL中的常见数据类型&#xff08;数值类型、文本二进制类型、时间日期、字符串类型&#xff09;&#xff0c;以及对表的约束&#xff08;非空约束、默认约束、列描述、零填充约束、自增长约束、主键约束、唯一键约束、外键约束&#xff09;。  …