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

设计模式行为型-状态模式

文章目录

  • 简介
  • 状态模式基础
    • 定义状态接口或抽象类
      • 实现具体状态类
  • 上下文类与状态转换
    • 上下文类的定义和作用
    • 状态转换及触发条件
  • 状态模式的优势与适用性
    • 优点一:可维护的代码
    • 优点二:清晰的状态管理
    • 适用场景一:对象拥有多个状态
    • 适用场景二:状态转换频繁且复杂
  • 具体业务场景应用:电商订单状态切换
  • 状态模式与其他设计模式的结合
    • 策略模式与状态模式的对比与联系
    • 工厂模式与状态模式的结合实践
  • 总结

简介

  • 状态模式是一种行为型设计模式,用于处理对象在不同状态下的行为变化。它将对象的行为封装在不同状态类中,通过状态的切换实现不同行为的触发。
  • 本文将介绍状态模式的基本概念、应用场景以及优势与适用性。
    在这里插入图片描述

状态模式基础

定义状态接口或抽象类

public abstract class State{public abstract void WriteProgram(Work w);}

实现具体状态类

    //上午工作状态public class ForenoonState : State{public override void WriteProgram(Work w){
//这里的判断就是决定要用那种行为展现出来,如果 不符合当前状态,那么就去到已经设置好的下一个具体状态类中进行相同的操作。if (w.hour < 12){Console.WriteLine("当前时间:{0}点 上午工作,精神百倍",w.Hour);}else{w.SetState(new NoonState());w.WriteProgram();}}}//中午工作状态public class NoonState : State{public override void WriteProgram(Work w){if (w.hour < 13){Console.WriteLine("当前时间:{0}点 饿了,想吃饭;犯困,想睡觉。", w.Hour);}else{w.SetState(new AfternoonState()); w.WriteProgram();}}}//下午工作状态public class AfternoonState : State{public override void WriteProgram(Work w){if (w.hour < 17){Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力", w.Hour);}else{w.SetState(new EveningState()); w.WriteProgram();}}}//晚上工作状态public class EveningState : State{public override void WriteProgram(Work w){if (w.finish ){w.SetState(new RestState());w.WriteProgram();//完成任务就转成下班状态}else{if (w.hour <21){Console.WriteLine("当前时间:{0}点 加班了,加班人累啊", w.Hour);}else {w.SetState(new SleepingState()); w.WriteProgram();//超过21点,转入睡眠状态}}}}//睡眠状态public class SleepingState:State{public override void WriteProgram(Work w){Console.WriteLine("当前时间:{0}点 不行了,睡着了", w.Hour);}}//下班休息状态public class RestState : State{public override void WriteProgram(Work w){Console.WriteLine("当前时间:{0}点 不行了,睡着了", w.Hour);}}

具体工作类:

    public class Work{public State current;public Work(){current = new ForenoonState();	//初始化为上午9点开始上班}public double hour;//小时钟,状态转换的依据public bool finish = false;//完成任务属性,是否能下班的依据//这个方法主要就是把具体的状态类给进来,然后让下面的方法去使用public void SetState(State s)	//得到状态{current = s;}
//下面这个方法从始至终都没有发生改变,改变是其内部具体的展现值。public void WriteProgram() {current.WriteProgram(this);}}

上下文类与状态转换

上下文类的定义和作用

  • 上下文类包含状态对象的引用,并将具体行为委托给当前状态对象执行。
  • 示例代码:
// 上下文类
public class Context {private State currentState;public void setCurrentState(State state) {this.currentState = state;}public void request() {// 委托当前状态对象执行行为currentState.handle();}
}

状态转换及触发条件

  • 状态转换指从一个状态切换到另一个状态的过程。
  • 触发条件是使状态转换发生的条件。
  • 示例代码:
// 具体状态类A
public class ConcreteStateA implements State {// ...@Overridepublic void handle() {// 具体状态A的行为逻辑// 状态转换及触发条件if (/*触发条件*/) {context.setCurrentState(new ConcreteStateB());}}
}

状态模式的优势与适用性

优点一:可维护的代码

  • 状态模式将每个状态的行为逻辑封装在独立的状态类中,易于理解和维护。

优点二:清晰的状态管理

  • 状态模式通过上下文类进行状态转换和行为委托,使状态管理更加清晰明确。

适用场景一:对象拥有多个状态

  • 当对象具有多个状态且不同状态下表现出不同行为时,可以使用状态模式进行状态管理和行为切换。

适用场景二:状态转换频繁且复杂

  • 当状态转换频繁且存在复杂的触发条件时,状态模式能够提供一种结构化的方式来管理状态转换。

具体业务场景应用:电商订单状态切换


为了演示订单状态管理的状态模式业务代码,我将使用Java语言来实现。以下是一个简单的示例:

首先,我们定义订单状态接口 OrderState,其中包含了处理订单状态的方法 handle()

// 订单状态接口
public interface OrderState {void handle();
}

然后,我们创建具体的订单状态类,包括待支付状态、已支付状态、待发货状态和已发货状态。每个状态类实现了订单状态接口,并根据相应的状态实现了自己的行为逻辑。

// 待支付状态类
public class PendingPaymentState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待支付");// 处理待支付状态的逻辑}
}// 已支付状态类
public class PaidState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已支付");// 处理已支付状态的逻辑}
}// 待发货状态类
public class ToBeShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待发货");// 处理待发货状态的逻辑}
}// 已发货状态类
public class ShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已发货");// 处理已发货状态的逻辑}
}

接下来,我们创建订单类 Order,它包含了当前订单状态和一些操作方法。

// 订单类
public class Order {private OrderState currentState; // 当前订单状态public Order() {currentState = new PendingPaymentState(); // 默认初始状态为待支付}public void setCurrentState(OrderState state) {currentState = state;}public void request() {currentState.handle();}
}

最后,我们可以进行测试,模拟订单在不同状态下的行为变化:

public class Main {public static void main(String[] args) {Order order = new Order(); // 创建订单// 待支付状态order.request();// 支付订单,状态转换为已支付order.setCurrentState(new PaidState());order.request();// 发货,状态转换为待发货order.setCurrentState(new ToBeShippedState());order.request();// 完成发货,状态转换为已发货order.setCurrentState(new ShippedState());order.request();}
}

运行以上代码,将得到如下输出:
在这里插入图片描述

以上示例演示了订单状态管理的状态模式业务代码。通过状态模式,我们可以根据订单状态的变化触发不同的行为逻辑,并且可以方便地添加新的订单状态,以满足业务需求。

状态模式与其他设计模式的结合

策略模式与状态模式的对比与联系

策略模式和状态模式都属于行为型设计模式,它们都关注对象在不同的情境下具有不同的行为。虽然它们有相似之处,但在设计意图、应用场景和实现方式上存在一些差异。

下面是策略模式和状态模式的对比与联系:

对比:

  1. 设计意图:策略模式旨在通过定义一组算法或策略,并将其封装成独立的对象,使得这些算法可以互换使用。状态模式旨在让一个对象在其内部状态改变时改变其行为,从而实现状态之间的转换。

  2. 关注点:策略模式主要关注算法的选择和封装,使得具体的策略可以独立于客户端进行变化。状态模式主要关注对象的状态的管理和转换,以及不同状态下的行为执行。

  3. 对象角色:策略模式通常包含一个上下文类(Context)和一组策略类(Strategies),客户端与上下文类进行交互。状态模式通常包含一个上下文类(Context)和一组状态类(States),客户端与上下文类进行交互。

联系:

  1. 行为的封装:策略模式和状态模式都将行为封装到独立的对象中,使得行为可以被动态地变化。

  2. 对象之间的互动:策略模式和状态模式都需要一个上下文类(Context)来与策略对象或状态对象进行交互,并将具体的行为委托给策略对象或状态对象来执行。

  3. 可扩展性:策略模式和状态模式都具有较好的可扩展性。在策略模式中,可以方便地新增、修改或切换不同的策略对象。在状态模式中,可以方便地新增、修改或切换不同的状态对象。

总的来说,策略模式和状态模式都是强调对象行为的灵活性和可扩展性的设计模式。它们的主要区别在于策略模式关注算法的选择和封装,而状态模式关注对象状态的管理和转换。根据具体的需求,选择适合的模式来提高代码的可维护性和可扩展性。

工厂模式与状态模式的结合实践

  • 结合工厂模式可以实现状态类的动态创建和切换,增强了状态模式的灵活性和可扩展性。
    结合工厂模式可以实现状态类的动态创建和切换,从而增强了状态模式的灵活性和可扩展性。工厂模式可以将状态对象的创建和状态转换逻辑与客户端代码分离,使得系统更加可维护和可扩展。

下面是一个示例,演示了如何结合工厂模式和状态模式来管理订单的状态:

首先,定义订单状态接口 OrderState 和具体的订单状态类,与之前的示例相同。

// 订单状态接口
public interface OrderState {void handle();
}// 待支付状态类
public class PendingPaymentState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待支付");// 处理待支付状态的逻辑}
}// 已支付状态类
public class PaidState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已支付");// 处理已支付状态的逻辑}
}// 待发货状态类
public class ToBeShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待发货");// 处理待发货状态的逻辑}
}// 已发货状态类
public class ShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已发货");// 处理已发货状态的逻辑}
}

然后,创建一个工厂类 OrderStateFactory,用于动态创建订单状态对象。
在严格意义上这个工厂是一个不支持扩充的,但是在这里仅作为一个示例,如果想要真正达到动态创建还是需要用到工厂方法,这里只能算是一个简单工厂。

// 订单状态工厂类  
public class OrderStateFactory {public static OrderState createOrderState(String stateName) {switch (stateName.toLowerCase()) {case "pendingpayment":return new PendingPaymentState();case "paid":return new PaidState();case "tobeshipped":return new ToBeShippedState();case "shipped":return new ShippedState();default:throw new IllegalArgumentException("Invalid state name");}}
}

接下来,我们可以使用上述的状态类和工厂类进行订单状态切换的实践:

public class Main {public static void main(String[] args) {Order order = new Order(); // 创建订单// 设置待支付状态order.setCurrentState(OrderStateFactory.createOrderState("PendingPayment"));order.request();// 支付订单,切换到已支付状态order.setCurrentState(OrderStateFactory.createOrderState("Paid"));order.request();// 发货,切换到待发货状态order.setCurrentState(OrderStateFactory.createOrderState("ToBeShipped"));order.request();// 完成发货,切换到已发货状态order.setCurrentState(OrderStateFactory.createOrderState("Shipped"));order.request();}
}

通过工厂模式,我们可以根据状态名称动态地创建不同的订单状态对象,并将其设置为上下文类的当前状态。这样,如果要新增或修改订单状态,只需要修改工厂类的代码,而不需要修改客户端的代码。这增强了状态模式的灵活性和可扩展性。

总结

  • 状态模式是一种有助于管理对象不同状态下行为变化的设计模式。通过将状态和行为封装在不同状态类中,状态模式提供了一种结构化的方式来处理状态转换和行为委托。它适用于对象拥有多个状态且状态转换复杂的场景,并与其他设计模式如策略模式、工厂模式等相结合能够进一步扩展其功能和灵活性。

相关文章:

设计模式行为型-状态模式

文章目录 简介状态模式基础定义状态接口或抽象类实现具体状态类 上下文类与状态转换上下文类的定义和作用状态转换及触发条件 状态模式的优势与适用性优点一&#xff1a;可维护的代码优点二&#xff1a;清晰的状态管理适用场景一&#xff1a;对象拥有多个状态适用场景二&#x…...

弹窗、抽屉、页面跳转区别 | web交互入门

当用户点击或触发浏览页面的某个操作&#xff0c;有很多web交互方式&#xff0c;可以大致分为弹窗、抽屉、跳转新页面三种web交互方式。虽然这三种web交互方式看起来没什么不同&#xff0c;但实际上弹窗、抽屉、跳转新页面对交互体验有蛮大的影响。 这需要UI\UX设计师针对不同…...

说说Flink运行模式

分析&回答 1.开发者模式 在idea中运行Flink程序的方式就是开发模式。 2.local-cluster模式 Flink中的Local-cluster(本地集群)模式,单节点运行&#xff0c;主要用于测试, 学习。 3.Standalone模式 独立集群模式&#xff0c;由Flink自身提供计算资源。 4.Yarn模式 把Fl…...

视频汇聚/视频云存储/视频监控管理平台EasyCVR新增首次登录强制修改密码

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚平台既具…...

C语言控制语句——分支语句

条件语句用来根据不同的条件来执行不同的语句&#xff0c;C语言中常用的条件语句包括if语句和switch语句。 if 语句 语法格式&#xff1a; if (条件) {条件成立时&#xff0c;要做的事…… }案例需求&#xff1a; 定义一个整数变量记录年龄判断是否满 18 岁 &#xff08;>…...

音视频 fmpeg命令裁剪和合并视频

一、生成测试文件 找三个不同的视频每个视频截取10秒内容 ffmpeg -i 沙海02.mp4 -ss 00:05:00 -t 10 -codec copy 1.mp4 ffmpeg -i 复仇者联盟3.mp4 -ss 00:05:00 -t 10 -codec copy 2.mp4 ffmpeg -i 红海行动.mp4 -ss 00:05:00 -t 10 -codec copy 3.mp4如果音视频格式不统一…...

机器学习基础17-基于波士顿房价(Boston House Price)数据集训练模型的整个过程讲解

机器学习是一项经验技能&#xff0c;实践是掌握机器学习、提高利用机器学习 解决问题的能力的有效方法之一。那么如何通过机器学习来解决问题呢&#xff1f; 本节将通过一个实例来一步一步地介绍一个回归问题。 本章主要介绍以下内容&#xff1a; 如何端到端地完成一个回归问题…...

哈希的应用——布隆过滤器

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;数据结构——位图 ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;布隆过滤器是由布隆&#xff08;Burton Howard Bloom&…...

LNMT的多机部署和双机热备

目录 一、环境 二、配置tomcat 三、配置nfs共享 四、配置nginx 1、两台都需要折磨配置 2、在http下面插入这两条信息 五、配置keepalived 1、安装 2、重新启动一下keepalived查看IP 六、验证双机热备 1、查看调度器备的IP&#xff0c;ip漂移说明keepalived生效 2、访…...

软件测试/测试开发丨Pytest和Allure报告 学习笔记

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/26755 Pytest 命名规则 类型规则文件test_开头 或者 _test 结尾类Test 开头方法/函数test_开头注意&#xff1a;测试类中不可以添加__init__构造函数 注…...

十七、命令模式

一、什么是命令模式 命令&#xff08;Command&#xff09;模式的定义&#xff1a;将一个请求封装为一个对象&#xff0c;使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通&#xff0c;这样方便将命令对象进行储存、传递、调用、增加与管理。   命令…...

服务器安装 anaconda 及 conda: command not found [解决方案]

[解决方案] conda: command not found Anaconda3 安装conda: command not found Anaconda3 安装 由于连接的服务器&#xff0c;无法直接在anaconda官网上下载安装文件&#xff0c;所以使用如下方法&#xff1a; wget https://repo.anaconda.com/archive/Anaconda3-2023.03-Li…...

自动驾驶和辅助驾驶系统的概念性架构(二)

摘要&#xff1a; 本篇为第二部分主要介绍底层计算单元、示例工作负载 前言 本文档参考自动驾驶计算联盟(Autonomous Vehicle Computing Consortium)关于自动驾驶和辅助驾驶计算系统的概念系统架构。该架构旨在与SAE L1-L5级别的自动驾驶保持一致。本文主要介绍包括功能模块图…...

【c++】VC编译出的版本,发布版本如何使用

目录 使用release类型进行发布 应用程序无法正常启动 0xc000007b 版本对应 vcruntime140d 应用版本 参考文章 使用release类型进行发布 应用程序无法正常启动 0xc000007b "应用程序无法正常启动 0xc000007b" 错误通常是一个 Windows 应用程序错误&#xf…...

自然语言处理(五):子词嵌入(fastText模型)

子词嵌入 在英语中&#xff0c;“helps”“helped”和“helping”等单词都是同一个词“help”的变形形式。“dog”和“dogs”之间的关系与“cat”和“cats”之间的关系相同&#xff0c;“boy”和“boyfriend”之间的关系与“girl”和“girlfriend”之间的关系相同。在法语和西…...

Zabbix“专家坐诊”第202期问答汇总

问题一 Q&#xff1a;请问一下 zabbix 里面怎么能创建出和sh文件有关联的监控项&#xff1f; A&#xff1a; 1.使用 Zabbix Agent 主动模式&#xff1a;如果你在目标主机上安装了 Zabbix Agent&#xff0c;并且想要监控与 sh 文件相关的指标&#xff0c;可以创建一个自定义的…...

【c语言】输出n行按如下规律排列的数

题述&#xff1a;输出n行按如下规律排列的数 输入&#xff1a; 4(应该指的是n) 输出: 思路&#xff1a; 利用下标的规律求解&#xff0c;考察数组下标的灵活应用&#xff0c;我们可以看出数从1开始是斜着往下放的&#xff0c;那么我们如何利用两层for循环求解这道题&#xff…...

023 - STM32学习笔记 - 扩展外部SDRAM(二) - 扩展外部SDRAM实验

023- STM32学习笔记 - 扩展外部SDRAM&#xff08;一&#xff09; - 扩展外部SDRAM实验 本节内容中要配置的引脚很多&#xff0c;如果你用的开发板跟我的不一样&#xff0c;请详细参照STM32规格书中说明对相关GPIO引脚进行配置。 先提前对本届内容的变成步骤进行总结如下&…...

机器学习 | Python实现XGBoost极限梯度提升树模型答疑

机器学习 | MATLAB实现XGBoost极限梯度提升树模型答疑 目录 机器学习 | MATLAB实现XGBoost极限梯度提升树模型答疑问题系列问题回答问题系列 关于XGBoost有几个问题想请教一下。1.XGBoost的API有哪些种调用方法?2.参数如何调? 问题回答 XGBoost的API有2种调用方法,一种是我们…...

关于使用远程工具连接mysql数据库时,提示:Public Key Retrieval is not allowed

我在使用DBeaver工具连接 数据库时&#xff0c;提示&#xff1a;Public Key Retrieval is not allowed&#xff0c; 我在前一天还是可以连接的&#xff0c;但是今天突然无法连接了&#xff0c; 但是最后捣鼓了一下又可以了。 具体方法&#xff1a;首先先把mysql服务停了&#x…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...