【设计模式】状态模式

文章目录

  • 引例
  • 状态模式理论
  • 状态模式代码优化
    • 结合享元模式
    • 并发问题解决
  • 策略模式 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.xdnf.cn/news/823782.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

IP地理位置定位技术基本原理

IP地理位置定位技术的基本原理是基于IP地址的特性。每个IP地址在网络中都有一个与之对应的地理位置信息&#xff0c;这是通过IP地址数据库来确定的。这个数据库由ISP&#xff08;Internet Service Provider&#xff09;或其它一些机构维护&#xff0c;其中包含了每个IP地址的地…

【LeetCode】修炼之路-0001-Two Sum(两数之和)【python】【简单】

前言 计算机科学作为一门实践性极强的学科,代码能力的培养尤为重要。当前网络上有非常多优秀的前辈分享了LeetCode的最佳算法题解,这对于我们这些初学者来说提供了莫大的帮助,但对于我这种缺乏编程直觉的学习者而言,这往往难以消化吸收。&#xff08;为什么别人就能想出这么优雅…

迷宫问题的对比实验研究(代码注释详细、迷宫及路径可视化)

题目描述 对不同的迷宫进行算法问题&#xff0c;广度优先、深度优先、以及人工智能上介绍的一些算法&#xff1a;例如A*算法&#xff0c;蚁群算法等。 基本要求&#xff1a; &#xff08;1&#xff09;从文件读入9*9的迷宫&#xff0c;设置入口和出口&#xff0c;分别采用以上方…

懒加载的el-tree中没有了子节点之后还是有前面icon箭头的展示,如何取消没有子节点之后的箭头显示

没有特别多的数据 <template><el-tree:props"props":load"loadNode"lazyshow-checkbox></el-tree></template><script>export default {data() {return {props: {label: name,children: zones,isLeaf:"leaf",//关…

华为服务器安装银河麒麟V10操作系统(IBMC安装)

iBMC是华为面向服务器全生命周期的服务器嵌入式管理系统。提供硬件状态监控、部署、节能、安全等系列管理工具&#xff0c;标准化接口构建服务器管理更加完善的生态系统。 服务器BMC IP&#xff1a;192.168.2.100 一、准备工作 1、确保本机和服务器BMC管理口在同一网络 2、银…

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解 目录 时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现贝叶斯变化点检测与时间序列分解 1.Matlab实现贝叶斯变化点检测与时间序列分解&#xff0c;完…

Windows下配置GCC(MinGW)环境

一、下载并安装MinGW 步骤1&#xff1a;下载MinGW安装器 前往MinGW的官方下载源&#xff0c;通过以下链接可以获取到最新版的MinGW安装程序&#xff1a; 网页地址&#xff1a;https://sourceforge.net/projects/mingw/files/ [MinGW 下载地址](https://sourceforge.net/proj…

单点登录的三种模式

介绍 单点登录存在的意义在于&#xff0c;比如公司里有多个系统&#xff0c;我只想登录一次&#xff0c;便可以访问公司的多个子系统 单点登录有很多模式&#xff0c;目前已知三种模式 1、cookie session模式 2、token模式 3、token refresh_token模式 Cookie Session模式…

go module本地包导入

go module本地包导入 本文目录 go module本地包导入启用go mod主项目工作目录本地module目录发布和使用模块 golang 1.11之后加入了go mod来替代GOPATH 官方文档参考&#xff1a;https://golang.google.cn/doc/tutorial/call-module-code 启用go mod 开启 Go modules # 临时开…

【Java】一文讲解Java类加载机制

Java 类加载机制是 Java 运行时的核心组成部分&#xff0c;负责在程序运行过程中动态加载和连接类文件&#xff0c;并将其转换为可执行代码。理解类加载机制&#xff0c;能更容易理解你一行行敲下的Java代码是如何在JVM虚拟机上运行起来。并且理解类加载机制之后&#xff0c;我…

Qt QAction添加图片

QAction用的时候&#xff0c;时常需要添加图片&#xff0c;如上图所示&#xff0c;代码如下所示&#xff1a; 测试的图片格式包含png,jpg,bmp,svg&#xff0c;其他未测试

C单片机数据类型与格式化

C语言数据类型 关键字位数表示范围stdint关键字ST关键字举例unsigned char80 ~ 255uint8_tu8u8 data 128char8-128 ~ 127int8_ts8s8 temperature 25unsigned short160 ~ 65535uint16_tu16u16 counter 5000short16-32768 ~ 32767int16_ts16s16 position 32767unsigned int3…

性能优化-如何提高cache命中率

本文主要介绍性能优化领域常见的cache的命中率问题&#xff0c;旨在全面的介绍提高cache命中率的方法&#xff0c;以供大家编写出性能友好的代码&#xff0c;并且可以应对性能优化领域的面试问题。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &am…

湘潭大学-2023年下学期-c语言-作业0x0a-综合1

A 求最小公倍数 #include<stdio.h>int gcd(int a,int b) {return b>0?gcd(b,a%b):a; }int main() {int a,b;while(~scanf("%d%d",&a,&b)){if(a0&&b0) break;printf("%d\n",a*b/gcd(a,b));}return 0; }记住最大公约数的函数&…

Hampel滤波器是一种基于中位数的离群值检测方法【异常值检测方法】

Hampel滤波器是一种基于中位数的离群值检测方法&#xff0c;也是一种线性滤波器&#xff0c;由德国数学家和统计学家John Hampel在1974年提出。它主要用于去除信号中的脉冲噪声&#xff0c;具有很强的抗干扰能力&#xff0c;因此被广泛应用于信号处理、通信系统等领域。 1.基本…

操作系统期末复习(100道)

(单选题)在计算机系统中配置操作系统的主要目的是&#xff08; &#xff09;。 A. 增强计算机系统的功能 B. 提高系统资源的利用率 C. 提高系统的运行速度 D. 合理组织系统的工作流程&#xff0c;以提高系统吞吐量 (单选题)操作系统的主要功能是管理计算机系统中的&#xff08…

WPF 消息日志打印帮助类:HandyControl+NLog+彩色控制台打印+全局异常捕捉

文章目录 前言相关文章Nlog配置HandyControl配置简单使用显示效果文本内容 全局异常捕捉异常代码运行结果 前言 我将简单的HandyControl的消息打印系统和Nlog搭配使用&#xff0c;简化我们的代码书写 相关文章 .NET 控制台NLog 使用 WPF-UI HandyControl 控件简单实战 C#更改…

【Unity动画系统】Animator有限状态机参数详解

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

Vue : 监视属性

目录 一个案例 监听属性 handler immediate vm.$watch(xxx) 深度监视 监视的简写 computed和watch之间的区别 一个案例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"…

RO-NeRF论文笔记

RO-NeRF论文笔记 文章目录 RO-NeRF论文笔记论文概述Abstract1 Introduction2 Related Work3 Method3.1 RGB and depth inpainting network3.2 Background on NeRFs3.3 Confidence-based view selection3.4 Implementation details 4 Experiments4.1 DatasetsReal ObjectsSynthe…