状态模式 (State Pattern)

定义

状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为。这种模式将每个状态的行为封装到对应的状态类中,使得上下文(Context)的行为随着其内部状态的改变而改变,看起来像是改变了其类。

结构

状态模式通常包含以下角色:

  • 上下文(Context):维护一个指向当前状态对象的引用,并将与状态相关的行为委托给当前状态对象。
  • 状态(State):定义一个接口,封装与上下文的一个特定状态相关的行为。
  • 具体状态(Concrete States):实现状态接口的类,每一个类封装了上下文对象的一个特定状态的行为。
解决的问题
  • 行为随状态改变
    • 当一个对象的行为依赖于其内部状态,并且需要在运行时根据状态的改变而改变行为时,状态模式提供了一种清晰的方式来实现这种依赖。
  • 状态逻辑分散问题
    • 在没有使用状态模式的情况下,对象的状态逻辑常常分散在整个对象中,尤其是在对象的行为受多个状态影响时。状态模式通过将每个状态的行为封装在单独的类中,使得状态相关的逻辑集中管理。
  • 复杂的条件选择结构
    • 状态模式帮助避免在对象的行为实现中使用复杂的条件选择结构(如if-else或switch-case语句)。通过将行为封装在状态对象中,可以使用多态替代条件语句。
  • 状态转换的显式表示
    • 状态模式使得状态的转换过程更加明确和显式。状态对象可以控制转换到下一个状态的逻辑,这样状态转换规则就不再隐含在对象的行为实现中。
  • 状态增加的灵活性
    • 使用状态模式时,新增状态只涉及添加一个新的状态类。这比在原有的条件逻辑中添加新的分支要清晰和简单得多,同时也更容易维护。
使用场景
  • 对象的行为取决于其状态
    • 当一个对象的行为随其内部状态的改变而改变时,状态模式是非常适用的。例如,一个文档可能有多种状态(如草稿、审阅、发布),每种状态下的行为(如编辑、审批、发布)都不同。
  • 复杂的条件分支控制
    • 当一个操作包含大量的条件分支,并且这些分支依赖于对象的状态时,使用状态模式可以避免复杂的条件分支逻辑,使得代码更易于理解和维护。
  • 状态的转换逻辑显式化
    • 如果状态转换的逻辑很复杂,或者有多个地方会触发状态转换,状态模式可以使这些逻辑集中管理,避免分散在系统的各个部分,从而降低出错的概率。
  • 状态机的实现
    • 对于那些可以用状态机来描述的系统,状态模式提供了一种清晰的实现方式。每个状态都是状态机的一个节点,状态转换则对应于状态机的边。
  • 减少代码重复
    • 如果在不同状态下的行为有重复代码,状态模式可以帮助组织和重用这些代码,尤其是当这些行为在状态间有细微差别时。
示例代码1-交通信号灯
// 状态接口
interface TrafficLightState {void change(TrafficLight trafficLight);
}// 具体状态:红灯
class RedLight implements TrafficLightState {public void change(TrafficLight trafficLight) {System.out.println("Red Light - Stop");trafficLight.setState(new GreenLight());}
}// 具体状态:绿灯
class GreenLight implements TrafficLightState {public void change(TrafficLight trafficLight) {System.out.println("Green Light - Go");trafficLight.setState(new YellowLight());}
}// 具体状态:黄灯
class YellowLight implements TrafficLightState {public void change(TrafficLight trafficLight) {System.out.println("Yellow Light - Caution");trafficLight.setState(new RedLight());}
}// 上下文
class TrafficLight {private TrafficLightState state;public TrafficLight(TrafficLightState state) {this.state = state;}public void setState(TrafficLightState state) {this.state = state;}public void change() {state.change(this);}
}// 客户端代码
public class TrafficLightDemo {public static void main(String[] args) {TrafficLight trafficLight = new TrafficLight(new RedLight());trafficLight.change(); // Red Light - StoptrafficLight.change(); // Green Light - GotrafficLight.change(); // Yellow Light - Caution}
}
示例代码2-文档状态管理
// 状态接口
interface DocumentState {void next(Document doc);void prev(Document doc);void printStatus();
}// 具体状态:草稿
class Draft implements DocumentState {public void next(Document doc) {doc.setState(new Review());}public void prev(Document doc) {System.out.println("The document is in its initial state.");}public void printStatus() {System.out.println("Document in Draft state.");}
}// 具体状态:审阅
class Review implements DocumentState {public void next(Document doc) {doc.setState(new Published());}public void prev(Document doc) {doc.setState(new Draft());}public void printStatus() {System.out.println("Document in Review state.");}
}// 具体状态:发布
class Published implements DocumentState {public void next(Document doc) {System.out.println("The document is already published.");}public void prev(Document doc) {doc.setState(new Review());}public void printStatus() {System.out.println("Document in Published state.");}
}// 上下文
class Document {private DocumentState state;public Document() {state = new Draft();}public void setState(DocumentState state) {this.state = state;}public void next() {state.next(this);}public void prev() {state.prev(this);}public void printStatus() {state.printStatus();}
}// 客户端代码
public class DocumentDemo {public static void main(String[] args) {Document document = new Document();document.printStatus(); // Document in Draft state.document.next();document.printStatus(); // Document in Review state.document.next();document.printStatus(); // Document in Published state.}
}
主要符合的设计原则
  • 开闭原则(Open-Closed Principle)
    • 状态模式允许在不修改现有代码的情况下添加新状态。这是因为你可以添加新的状态类来扩展系统的行为,而无需更改现有的上下文或其他状态类。因此,系统对于扩展是开放的,但对于修改是封闭的。
  • 单一职责原则(Single Responsibility Principle)
    • 在状态模式中,每个状态类仅负责管理与其状态相关的行为,而上下文类则负责维护状态和委托状态相关的任务。这样,每个类只有一个改变的原因,即它所代表的状态的行为,从而符合单一职责原则。
  • 里氏替换原则(Liskov Substitution Principle)
    • 状态模式中的每个具体状态都是通过状态接口或抽象状态类实现的,这意味着它们都可以互换使用。因此,任何时候都可以使用这些具体状态来替代状态接口,这符合里氏替换原则。
在JDK中的应用
  • java.util.Iterator
    • Iterator 接口的实现类通常会根据内部的集合状态(如集合的当前位置)来改变其行为。例如,在遍历过程中,hasNext()next() 方法的行为取决于迭代器的当前位置。
  • java.net.URLConnection
    • URLConnection 类及其子类有不同的状态,如连接前和连接后。在连接打开之后,尝试修改连接属性(如调用 setDoOutput() 方法)将抛出异常,表明其行为随状态变化。
  • java.nio.channels.Selector
    • 在Java NIO中,Selector 类的行为依赖于它当前的状态(如打开或关闭状态)。选择器的某些操作只在打开状态下有效,而在关闭状态下会有不同的行为或抛出异常。
在Spring中的应用
  • Spring Web Flow
    • Spring Web Flow是Spring框架的一个扩展,它管理着基于状态的流程。在这种情况下,根据当前流程的状态(如步骤或页面),应用程序的行为会有所不同。Spring Web Flow通过定义状态和转换来管理复杂的流程逻辑。
  • Spring状态机(Spring State Machine)
    • Spring State Machine提供了一种系统化的方式来实现状态模式,允许定义状态、事件和在不同状态下触发的行为。虽然这是一个独立的项目,但它与Spring框架集成,为实现基于状态的逻辑提供了更结构化的方法。
  • Spring Security的认证流程
    • 在Spring Security中,认证和授权流程可能根据不同的状态(如已认证、未认证、授权失败)执行不同的逻辑。例如,不同的认证提供者可以根据上下文或安全令牌的状态来决定认证逻辑。
  • Spring Session
    • 在Spring Session中,会话的状态(如新建、已存在、过期)可以决定某些行为(如会话创建、会话获取、会话失效)。

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

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

相关文章

公众号违禁词及违规行为汇总

1、微信官方发布《微信公众平台关于清理集赞行为的公告》,全面禁止公众账号“集赞”玩法。 微信对违反微信用户协议和公众平台协议的公众号处理机制是,公众号累计发现一次有集赞行为,封号7天;公众号累计发现二次有集赞行为&#…

面试:ShardingSphere问题

文章目录 什么是ShardingSphere,它的主要功能是什么?ShardingSphere的核心模块有哪些?他们是如何工作的?ShardingSphere 的读写分离是如何实现的?如何配置ShardingSphere的数据分片策略?ShardingSphere支持…

【运维面试100问】(六)buffer和cache的区别

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》:python零基础入门学习 《python运维脚本》: python运维脚本实践 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8…

【Linux】匿名管道+进程池

文章目录 前置知识一、管道的原理二、管道的特性三、管道的接口四、使用管道实现简单的进程池解决进程池的一个小问题 前置知识 一个进程在创建时,会默认打开三个文件,分别是:stdin,stdout,stderr 进程中有一个维护进…

1linux

Is查看目录内容 ls -ahil a表示全部,h表示文件大小以人类易读的形式给出,i表示索引节点,l表示长列表形式。 cd 切换目录 touch 创建文件 mkdir 创建目录 mkdir Makedirectory,创建目录,-p指定路径,-m指定权…

炫我出席数字光影工作室专业建设论坛,受聘为专家委员会委员!

11月18日,炫我科技受邀参加在北京深澜AI空间举办的2023数字光影工作室专业建设论坛。本次活动由北京市新媒体技师学院主办、北京澜景科技有限公司协办,私有云售前技术工程师龚琛代表我司出席,并受聘为新媒体技师学院数字光影工作室专家委员会…

Mysql基础操作(命令行)

文章目录 Mysql基础操作(命令行)背景创建数据库选择数据库查看所有表查看表结构向表插入数据插入第一条插入第二条插入第三条 查询表数据修改表数据删除表数据 Mysql基础操作(命令行) 背景 docker安装mysql8,映射本地…

ubuntu下,PX4使用 upload 下载代码没反应

可能原因,没有串口权限 sudo chmod 777 /dev/ttyACM0开启串口权限,本次问题解决。

GTC2023全球流量大会蓄势待发,菊风在7B57展位等你!

第六届 GTC 全球流量大会(以下简称 GTC2023)将于12月5日- 6日,在深圳福田会展中心7&8号馆举办。 据悉,本届大会将是历届以来规模最大、参与人数最多、跨境出海资源最丰富的一次行业盛会。7、8 号馆共 15000 平方米&am…

计算机组成原理-磁盘存储器

文章目录 总览外存储器磁盘存储器磁盘的性能指标磁盘地址磁盘的工作过程磁盘阵列 总结 总览 外存储器 磁盘存储器 写是利用电流产生磁场从而写磁盘 读是利用载磁体移动时产生的电场从而得到数据 磁性材质易受外界磁场干扰 下图中 载磁体上N S的前后顺序代表对应存储二进制的比…

【深度学习】卷积神经网络(CNN)的参数优化方法

著名: 本文是从 Michael Nielsen的电子书Neural Network and Deep Learning的深度学习那一章的卷积神经网络的参数优化方法的一些总结和摘录,并不是我自己的结论和做实验所得到的结果。我想Michael的实验结果更有说服力一些。本书在github上有中文翻译的…

【不同请求方式在springboot中对应的注解】

GET 请求方法&#xff1a;用于获取资源。使用 GetMapping 注解来处理 GET 请求。 示例代码&#xff1a; RestController public class MyController {GetMapping("/resource")public ResponseEntity<String> getResource() {// 处理 GET 请求逻辑} }POST 请求方…

喜讯!云起无垠成为国家信息安全漏洞库(CNNVD)技术支撑单位

近日&#xff0c;云起无垠凭借其在漏洞挖掘、漏洞检测以及漏洞修复等领域的卓越表现&#xff0c;荣获“国家信息安全漏洞库&#xff08;CNNVD&#xff09;技术支撑单位等级证书&#xff08;三级&#xff09;”&#xff0c;正式成为CNNVD技术支撑单位。 中国国家信息安全漏洞库&…

MTK联发科MT6762/MT6763/MT6765安卓核心板参数规格比较

MT6762安卓核心板 MTK6762安卓核心板是一款工业级高性能、可运行 android9.0 操作系统的 4G智能模块。 CPU&#xff1a;4xCortex-A53 up to 2.0Ghz/4xCortex-A53 up to 1.5GhzGraphics&#xff1a;IMG GE8320 Up to 650MhzProcess&#xff1a;12nmMemory&#xff1a;1xLP3 9…

【正点原子STM32连载】 第六十章 串口IAP实验(Julia分形)实验 摘自【正点原子】APM32F407最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子APM32F407最小系统板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html## 第六十…

CMake使用file(GLOB ...)需要注意的问题

文章目录 基本语法使用例子潜在的问题大型项目中推荐的用法 file(GLOB ...) 命令用于获取匹配指定模式的文件列表。在 CMake 中&#xff0c;file(GLOB ...) 命令的一种常见用法是用于收集源文件列表&#xff0c;例如 C 源文件&#xff08;.cpp&#xff09;和 C 源文件&#xff…

html页面加载json数据,在html中显示JSON数据的方法

html页面加载json数据,在html中显示JSON数据的方法 export const mixin {methods: {syntaxHighlight(json) {if (typeof json ! string) {json JSON.stringify(json, undefined, 2);}json json.replace(/&/g, &).replace(/</g, <).replace(/>/g, >);re…

实例分割12篇顶会论文及代码合集,含2023最新

同学们&#xff0c;你们觉得视觉经典四个任务中哪个最难&#xff1f;我个人觉得是实例分割。 因为它既具备语义分割的特点&#xff0c;需要做到像素层面上的分类&#xff0c;也具备目标检测的一部分特点&#xff0c;即需要定位出不同实例&#xff0c;即使它们是同一种类。 但…

LangChain的函数,工具和代理(一):OpenAI的函数调用

一、什么是函数调用功能 几个月前OpenAI官方发布了其API的函数调用功能(Function calling), 在 API 调用中&#xff0c;您可以描述函数&#xff0c;并让模型智能地选择输出包含调用一个或多个函数的参数的 JSON 对象。API函数“ChatCompletion” 虽然不会实际调用该函数&#…